diff --git a/__snapshots__/test.ts.snap b/__snapshots__/test.ts.snap index 5115bc47..477d0b3f 100644 --- a/__snapshots__/test.ts.snap +++ b/__snapshots__/test.ts.snap @@ -180,6 +180,7 @@ Object { ], "taskNumber": 2, }, + "timezone": 0, } `; diff --git a/fixtures/20241007TZN.igc b/fixtures/20241007TZN.igc new file mode 100644 index 00000000..9e6da7a5 --- /dev/null +++ b/fixtures/20241007TZN.igc @@ -0,0 +1,216 @@ +AXSX004 SKYTRAXX +HFPLTPILOT:Stefan Walter +HFDTM100GPSDATUM:WGS-84 +HFRFWFIRMWAREVERSION:202401301017 +HFRHWHARDWAREVERSION:2.1 +HFTZNTIMEZONE:+5.50 +HFSITSITE:Bir_Billing_Golf Cour +HFDTE071024 +B0626473205699N07642351EA0222802387 +B0626483205699N07642351EA0222802387 +B0626493205699N07642351EA0222802388 +B0626503205699N07642351EA0222802388 +B0626513205699N07642351EA0222802387 +B0626523205699N07642351EA0222802387 +B0626533205699N07642351EA0222802387 +B0626543205699N07642351EA0222802388 +B0626553205698N07642351EA0222802388 +B0626563205698N07642351EA0222802388 +B0626573205698N07642350EA0222702387 +B0626583205697N07642350EA0222702386 +B0626593205697N07642349EA0222602386 +B0627003205697N07642348EA0222602386 +B0627013205697N07642347EA0222602386 +B0627023205696N07642345EA0222302383 +B0627033205694N07642344EA0222102381 +B0627043205691N07642342EA0222102380 +B0627053205688N07642340EA0221902378 +B0627063205685N07642336EA0221502375 +B0627073205683N07642330EA0221302373 +B0627083205679N07642326EA0221502374 +B0627093205676N07642321EA0221402374 +B0627103205673N07642318EA0221402374 +B0627113205668N07642315EA0221402373 +B0627123205665N07642312EA0221202372 +B0627133205661N07642308EA0221102371 +B0627143205657N07642305EA0221102371 +B0627153205653N07642301EA0221002370 +B0627163205649N07642297EA0221102371 +B0627173205646N07642293EA0221102371 +B0627183205642N07642289EA0221202372 +B0627193205640N07642285EA0221102371 +B0627203205636N07642282EA0221102371 +B0627213205633N07642278EA0221002370 +B0627223205629N07642274EA0220902369 +B0627233205625N07642271EA0221002370 +B0627243205622N07642267EA0221102371 +B0627253205619N07642264EA0221202372 +B0627263205615N07642262EA0221202372 +B0627273205612N07642259EA0221202371 +B0627283205609N07642255EA0221202372 +B0627293205605N07642251EA0221302372 +B0627303205601N07642247EA0221302373 +B0627313205598N07642243EA0221502375 +B0627323205594N07642242EA0221602375 +B0627333205590N07642240EA0221702376 +B0627343205586N07642239EA0221802378 +B0627353205582N07642239EA0221902379 +B0627363205578N07642241EA0222102381 +B0627373205576N07642243EA0222202382 +B0627383205574N07642247EA0222202382 +B0627393205574N07642252EA0222302382 +B0627403205574N07642257EA0222002380 +B0627413205576N07642263EA0221902379 +B0627423205580N07642269EA0221902379 +B0627433205586N07642272EA0222002380 +B0627443205592N07642273EA0222002380 +B0627453205598N07642271EA0222202382 +B0627463205604N07642269EA0222202381 +B0627473205609N07642264EA0222302383 +B0627483205614N07642259EA0222402384 +B0627493205618N07642253EA0222602386 +B0627503205621N07642248EA0222802388 +B0627513205625N07642244EA0223002390 +B0627523205628N07642239EA0223002390 +B0627533205630N07642234EA0223102391 +B0627543205634N07642230EA0223102390 +B0627553205639N07642226EA0223102391 +B0627563205644N07642223EA0223102390 +B0627573205650N07642221EA0223202392 +B0627583205655N07642220EA0223302392 +B0627593205660N07642220EA0223202392 +B0628003205665N07642219EA0223002390 +B0628013205671N07642219EA0222802388 +B0628023205677N07642219EA0222802388 +B0628033205683N07642219EA0223002390 +B0628043205688N07642220EA0223202391 +B0628053205693N07642221EA0223202392 +B0628063205697N07642224EA0223202392 +B0628073205702N07642226EA0223102390 +B0628083205707N07642230EA0222902388 +B0628093205711N07642236EA0222602386 +B0628103205714N07642242EA0222602385 +B0628113205716N07642249EA0222702387 +B0628123205717N07642256EA0222802388 +B0628133205717N07642262EA0223002390 +B0628143205717N07642267EA0222902389 +B0628153205718N07642272EA0222902388 +B0628163205720N07642278EA0222902389 +B0628173205724N07642283EA0222802387 +B0628183205728N07642287EA0222802387 +B0628193205732N07642291EA0223002390 +B0628203205734N07642295EA0223002390 +B0628213205733N07642301EA0222902388 +B0628223205731N07642307EA0222802388 +B0628233205728N07642311EA0222802388 +B0628243205725N07642314EA0223002390 +B0628253205722N07642315EA0223202391 +B0628263205720N07642319EA0223002390 +B0628273205717N07642321EA0222802387 +B0628283205713N07642326EA0222602386 +B0628293205710N07642330EA0222702387 +B0628303205709N07642334EA0222802387 +B0628313205707N07642336EA0222602385 +B0628323205705N07642338EA0222302383 +B0628333205703N07642339EA0222402384 +B0628343205703N07642340EA0222502385 +B0628353205703N07642340EA0222502384 +B0628363205703N07642340EA0222502385 +B0628373205703N07642340EA0222502385 +B0628383205703N07642340EA0222502385 +B0628393205703N07642340EA0222502385 +B0628403205703N07642340EA0222502385 +B0628413205703N07642340EA0222502385 +B0628423205703N07642340EA0222502385 +B0628433205703N07642341EA0222502385 +B0628443205703N07642341EA0222502385 +B0628453205703N07642341EA0222602386 +B0628463205703N07642341EA0222602386 +B0628473205703N07642342EA0222602386 +B0628483205703N07642342EA0222602386 +B0628493205703N07642343EA0222602386 +B0628503205704N07642343EA0222702387 +B0628513205704N07642344EA0222702387 +B0628523205704N07642344EA0222702387 +B0628533205704N07642345EA0222702387 +B0628543205704N07642344EA0222702387 +B0628553205704N07642344EA0222702387 +B0628563205704N07642345EA0222702387 +B0628573205704N07642345EA0222702387 +B0628583205704N07642345EA0222702387 +B0628593205703N07642345EA0222702387 +B0629003205703N07642345EA0222702387 +B0629013205703N07642345EA0222702387 +B0629023205703N07642345EA0222702387 +B0629033205703N07642346EA0222802388 +B0629043205703N07642347EA0222802388 +B0629053205703N07642347EA0222802388 +B0629063205703N07642348EA0222802388 +B0629073205702N07642348EA0222802388 +B0629083205702N07642349EA0222802388 +B0629093205702N07642349EA0222802388 +B0629103205702N07642350EA0222802388 +B0629113205702N07642350EA0222802388 +B0629123205702N07642351EA0222902389 +B0629133205702N07642351EA0222902389 +B0629143205702N07642352EA0222902389 +B0629153205702N07642352EA0222902389 +B0629163205702N07642353EA0222902389 +B0629173205701N07642353EA0222902389 +B0629183205701N07642354EA0222902389 +B0629193205701N07642355EA0222902389 +B0629203205701N07642355EA0222902389 +B0629213205701N07642355EA0222902389 +B0629223205701N07642356EA0223002390 +B0629233205701N07642356EA0223002390 +B0629243205702N07642357EA0223002390 +B0629253205702N07642357EA0223002390 +B0629263205702N07642358EA0223002390 +B0629273205702N07642358EA0223002390 +B0629283205702N07642358EA0223002390 +B0629293205702N07642358EA0223002390 +B0629303205702N07642357EA0223002390 +B0629313205702N07642358EA0223002390 +B0629323205702N07642358EA0223002390 +B0629333205702N07642358EA0223002390 +B0629343205702N07642359EA0223002390 +B0629353205702N07642359EA0223002390 +B0629363205702N07642359EA0223002390 +B0629373205702N07642359EA0223002390 +B0629383205702N07642358EA0223002390 +B0629393205702N07642358EA0223002390 +B0629403205702N07642358EA0223002390 +B0629413205702N07642358EA0223002390 +B0629423205702N07642357EA0223002390 +B0629433205702N07642357EA0223002390 +B0629443205702N07642357EA0223002390 +B0629453205702N07642356EA0223002390 +B0629463205703N07642356EA0223002390 +B0629473205703N07642356EA0223002390 +B0629483205703N07642356EA0223002390 +B0629493205702N07642356EA0223002390 +B0629503205702N07642356EA0223002390 +B0629513205702N07642356EA0223002390 +B0629523205701N07642356EA0223002390 +B0629533205701N07642356EA0223002390 +B0629543205701N07642356EA0223002390 +B0629553205700N07642356EA0222902389 +B0629563205700N07642356EA0222902389 +B0629573205700N07642356EA0222902389 +B0629583205700N07642356EA0222902389 +B0629593205700N07642356EA0222902389 +B0630003205700N07642356EA0222902389 +B0630013205700N07642356EA0222902389 +B0630023205700N07642356EA0222902389 +B0630033205700N07642356EA0222902389 +B0630043205700N07642356EA0222902389 +B0630053205700N07642356EA0222902389 +LXSX;S1;TS:1728282407;TL:1728282605;AS:2387;AL:2389;AT:2392;AB:2369 +LXSX;S1;XS:2;XD:0.74;SP:40.5;MC:1.0;MS:-1.2;NB:200 +LXSX;S1;FL:0.9;TG:0;TC:0.0 +LXSX;S1;X0:32.09498,76.70585 +LXSX;S1;X1:32.09293,76.70405 +LXSX;S1;X2:32.09488,76.70367 +LXSX;S1;X3:32.09500,76.70593 +LXSX;S1;X4:32.09500,76.70593 +GA36C26B28792C613E9BF3065DFB78ADF diff --git a/index.ts b/index.ts index 1c463b95..850dd3d7 100644 --- a/index.ts +++ b/index.ts @@ -16,6 +16,7 @@ const RE_SIT_HEADER = /^H(\w)SIT(?:.{0,}?:(.*)|(.*))$/; const RE_FTY_HEADER = /^H(\w)FTY(?:.{0,}?:(.*)|(.*))$/; const RE_RFW_HEADER = /^H(\w)RFW(?:.{0,}?:(.*)|(.*))$/; const RE_RHW_HEADER = /^H(\w)RHW(?:.{0,}?:(.*)|(.*))$/; +const RE_TZN_HEADER = /^H(\w)TZN(?:.{0,}?:([-+]?[\d.]+))$/; const RE_B = /^B(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{3})([NS])(\d{3})(\d{2})(\d{3})([EW])([AV])(-\d{4}|\d{5})(-\d{4}|\d{5})/; const RE_K = /^K(\d{2})(\d{2})(\d{2})/; const RE_IJ = /^[IJ](\d{2})(?:\d{2}\d{2}[A-Z]{3})+/; @@ -34,6 +35,7 @@ declare namespace IGCParser { /** UTC date of the flight in ISO 8601 format */ date: string; numFlight: number | null; + timezone: number | null; pilot: string | null; copilot: string | null; @@ -269,6 +271,8 @@ class IGCParser { this._result.competitionClass = this.parseCompetitionClass(line); } else if (headerType === 'SIT') { this._result.site = this.parseSite(line); + } else if (headerType === 'TZN') { + this._result.timezone = this.parseTimezone(line); } else if (headerType === 'FTY') { this._result.loggerType = this.parseLoggerType(line); } else if (headerType === 'RFW') { @@ -354,6 +358,14 @@ class IGCParser { return this.parseTextHeader('SIT', RE_SIT_HEADER, line); } + private parseTimezone(line: string): number { + let result = this.parseTextHeader('TZN', RE_TZN_HEADER, line); + let hours = parseFloat(result); + if (isNaN(hours)) + throw new Error(`Invalid TZN header at line ${this.lineNumber}: ${line}`); + return hours; + } + private parseLoggerType(line: string): string { return this.parseTextHeader('FTY', RE_FTY_HEADER, line); } diff --git a/test.ts b/test.ts index 9bfa91c2..aa44493a 100644 --- a/test.ts +++ b/test.ts @@ -104,6 +104,14 @@ describe('IGCParser', () => { expect(result).toMatchSnapshot(); }); + /* Test timezone parsing */ + test('20241007TZN.igc', () => { + let content = fs.readFileSync(`${__dirname}/fixtures/20241007TZN.igc`, 'utf8'); + let result = IGCParser.parse(content); + + expect(result.timezone).toEqual(5.5); + }); + test('MD_85ugkjj1.IGC', () => { let content = fs.readFileSync(`${__dirname}/fixtures/MD_85ugkjj1.IGC`, 'utf8'); let result = IGCParser.parse(content, { lenient: true });