Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added timezone/config/tzinfo
Binary file not shown.
11 changes: 11 additions & 0 deletions timezone/test.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
action,ms,bytes,lang,code,repeat,minver,comment
before,0,0,q,.timezone.init[],1,,Initialize package
true,0,0,q,0<count .timezone.offsets,1,,Confirm tzinfo is read in properly
true,0,0,q,400<count .timezone.zones,1,,Confirm distinct time zones is populated and significant number available
true,0,0,q,2025.07.22D14:19:48.386221575=.timezone.localtogmt["America/New_York";2025.07.22D10:19:48.386221575],1,,Test local to gmt 1
true,0,0,q,1999.03.03D12:13:48.919241092=.timezone.localtogmt["Europe/London";1999.03.03D12:13:48.919241092],1,,Test local to gmt 2
true,0,0,q,1967.05.02D21:03:52.857237462=.timezone.gmttolocal["America/Toronto";1967.05.03D01:03:52.857237462],1,,Test gmt to local 1
true,0,0,q,2017.09.01D04:03:52.857237462=.timezone.gmttolocal["America/Los_Angeles";2017.09.01D11:03:52.857237462],1,,Test gmt to local 2
true,0,0,q,2025.07.21D19:19:48.386221575=.timezone.convert["Asia/Singapore";"America/Vancouver";2025.07.22D10:19:48.386221575],1,,Test timezone to timezone 1
true,0,0,q,2025.07.24D15:27:58.224707599=.timezone.convert["America/New_York";"America/Toronto";2025.07.24D15:27:58.224707599],1,,Test timezone to timezone 2
true,0,0,q,2025.11.02D01:30:00.000=.timezone.convert["America/New_York";"America/New_York";2025.11.02D01:30:00.000],1,,DST edge case
60 changes: 60 additions & 0 deletions timezone/timezone.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
## KDB+/Q Timezone Conversion Library

This project provides utilities to manage and convert timestamps across timezones in KDB+ using reference data from TimeZoneDB.

---

### TimeZoneDB Data Source

Timezone reference data is sourced from https://timezonedb.com/download and must be downloaded and provided to the package in order to function.
The downloadable .zip archive includes several files, but only time_zone.csv is used for core functionality.

There is a copy of tzinfo already in the package default subdirectory : timezone/config/tzinfo.
Should you need to update can follow the steps below.

Following transformations to save down and be formatted for the package:
```q
t:flip `timezoneID`gmtDateTime`gmtOffset`dst!("S JIB";csv)0:hsym `:time_zone.csv
`:tzinfo set t
`:tzinfo
```

---

### Package Initialization

Set the path to your timezone data file

```q
/ Overwrite tzinfo file path if neccessary
.timezone.config.file:"/your/output/directory/tzinfo"
/ Initalize package
.timezone.init[]
```

---

### Package Use

##### .timezone.localtogmt
Converts a local timestamp to GMT using timezoneID
```q
// .timezone.localtogmt[localTimezone;timestamp]
.timezone.localtogmt["America/New_York";2025.07.22D10:19:48.386221575]
2025.07.22D14:19:48.386221575
```

##### .timezone.gmttolocal
Converts a GMT timestamp to local using timezoneID
```q
// .timezone.gmttolocal[localTimezone;timestamp]
.timezone.gmttolocal["America/New_York";2025.07.22D10:19:48.386221575]
2025.07.22D06:19:48.386221575
```

##### .timezone.convert
```q
// .timezone.convert[sourceTimezone;destTimezone;timestamp]
.timezone.convert["America/New_York";"Europe/London";2025.07.22D10:19:48.386221575]
2025.07.22D15:19:48.386221575
```
37 changes: 37 additions & 0 deletions timezone/timezone.q
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/ library for converting between and managing timezones

/ override variables to change internal logic
.timezone.config.file:"timezone/config/tzinfo"; / filepath of timezone data to be downloaded with utility script

/ read and format file for internal function reference
.timezone.config.read:{
tz:get hsym `$.timezone.config.file;
tz:delete from tz where gmtDateTime>=10170056837;
tz:update gmtDateTime:12h$-946684800000000000+gmtDateTime*1000000000 from tz;
tz:update gmtOffset:16h$gmtOffset*1000000000 from tz;
tz:update localDateTime:gmtDateTime+gmtOffset from tz;
tz:`gmtDateTime xasc tz;
tz:update `g#timezoneID from tz;
tz
};

/ convert from local timestamp to gmt
.timezone.gmttolocal:{[tz;ts]
if[not (tz:`$tz) in .timezone.zones;'`notValidTimezone];
$[0>type ts;first;(::)]@exec gmtDateTime+gmtOffset from aj[`timezoneID`gmtDateTime;([]timezoneID:(),tz;gmtDateTime:ts,());.timezone.offsets]
};

/ convert from gmt to local timestamp
.timezone.localtogmt:{[tz;ts]
if[not (tz:`$tz) in .timezone.zones;'`notValidTimezone];
$[0>type ts;first;(::)]@exec localDateTime-gmtOffset from aj[`timezoneID`localDateTime;([]timezoneID:(),tz;localDateTime:ts,());.timezone.offsets]
};

/ convert between custom timestamps
.timezone.convert:{[stz;dtz;ts].timezone.gmttolocal[dtz;.timezone.localtogmt[stz;ts]]};

/ init function to read in timezone source data
.timezone.init:{
.timezone.offsets:@[.timezone.config.read;`;{'`cantImportTimeZoneData}];
.timezone.zones:exec distinct timezoneID from .timezone.offsets;
};