diff --git a/docs6/mkdocs.yml b/docs6/mkdocs.yml index 0a68ed38e..ba5578854 100644 --- a/docs6/mkdocs.yml +++ b/docs6/mkdocs.yml @@ -93,6 +93,7 @@ nav: - "DSL filter statements": "reference-dsl-filter-statements.md" - "DSL output statements": "reference-dsl-output-statements.md" - "DSL unset statements": "reference-dsl-unset-statements.md" + - "DSL datetime/timezone functions": "reference-dsl-time.md" - "DSL errors and transparency": "reference-dsl-errors.md" - "Differences from other programming languages": "reference-dsl-differences.md" - "A note on the complexity of Miller's expression language": "reference-dsl-complexity.md" diff --git a/docs6/src/record-heterogeneity.md b/docs6/src/record-heterogeneity.md index 752a70e46..3e5e1a3ad 100644 --- a/docs6/src/record-heterogeneity.md +++ b/docs6/src/record-heterogeneity.md @@ -127,8 +127,6 @@ If you `mlr csv cat` this, you'll get an error message: mlr --csv cat data/het/ragged.csv
-a,b,c -1,2,3 mlr : mlr: CSV header/data length mismatch 3 != 2 at filename data/het/ragged.csv row 3.diff --git a/docs6/src/reference-dsl-time.md b/docs6/src/reference-dsl-time.md new file mode 100644 index 000000000..ed57405ba --- /dev/null +++ b/docs6/src/reference-dsl-time.md @@ -0,0 +1,309 @@ + +
+mlr -n put 'end {
+ print sec2gmt(1500000000);
+ print sec2gmt(1500000000000);
+}'
+
++2017-07-14T02:40:00Z +49503-02-10T02:40:00Z ++ +You can get the current system time, as epoch-seconds, using the +[systime](reference-dsl-builtin-functions.md#systime) DSL function: + +
+mlr --c2p --from example.csv put '$t = systime()' ++
+color shape flag k index quantity rate t +yellow triangle true 1 11 43.6498 9.8870 1634784588.045347 +red square true 2 15 79.2778 0.0130 1634784588.045385 +red circle true 3 16 13.8103 2.9010 1634784588.045386 +red square false 4 48 77.5542 7.4670 1634784588.045393 +purple triangle false 5 51 81.2290 8.5910 1634784588.045394 +red square false 6 64 77.1991 9.5310 1634784588.045417 +purple triangle false 7 65 80.1405 5.8240 1634784588.045418 +yellow circle true 8 73 63.9785 4.2370 1634784588.045419 +yellow circle true 9 87 63.5058 8.3350 1634784588.045421 +purple square false 10 91 72.3735 8.2430 1634784588.045422 ++ +The [systimeint](reference-dsl-builtin-functions.md#systimeint) DSL functions +is nothing more than a keystroke-saver for `int(systime())`. + +# UTC times with standard format + +One way to make epoch-seconds human-readable, while maintaining some of their +benefits such as being independent of timezone and daylight savings, is to use +the [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) format. This was the +first (and initially only) human-readable date/time format supported by Miller +going all the way back to Miller 1.0.0. + +You can get these from epoch-seconds using the +[sec2gmt](reference-dsl-builtin-functions.md#sec2gmt) DSL function. +(Note that the terms _UTC_ and _GMT_ are used interchangeably in Miller.) +We also have [sec2gmtdate](reference-dsl-builtin-functions.md#sec2gmtdate) DSL function. + +
+mlr -n put 'end {
+ print sec2gmt(0);
+ print sec2gmt(1234567890.123);
+ print sec2gmt(-1234567890.123);
+ print;
+ print sec2gmtdate(0);
+ print sec2gmtdate(1234567890.123);
+ print sec2gmtdate(-1234567890.123);
+}'
+
++1970-01-01T00:00:00Z +2009-02-13T23:31:30Z +1930-11-18T00:28:29Z + +1970-01-01 +2009-02-13 +1930-11-18 ++ +# Local times with standard format; specifying timezones + +You can use similar formatting for dates in your preferred timezone, not just UTC/GMT. +We have the +[sec2localtime](reference-dsl-builtin-functions.md#sec2localtime), +[sec2localdate](reference-dsl-builtin-functions.md#sec2localdate), and +[localtime2sec](reference-dsl-builtin-functions.md#localtime2sec) DSL functions. + +You can specify the timezone using any of the following: + +* An environment variable, e.g. `export TZ=Asia/Istanbul` at your system prompt (`set TZ=Asia/Istanbul` in Windows) +* Using the `--tz` flag. This sets the `TZ` environment variable, but only internally to the `mlr` process +* Within a DSL expression, you can assign to `ENV["TZ"]`. + +Regardless, if you specifiy an invalid timezone, you'll be clearly notified: + +
+mlr --from example.csv --tz This/Is/A/Typo cat ++
+mlr: unknown time zone This/Is/A/Typo ++ +
+export TZ=Asia/Istanbul
+mlr -n put 'end { print sec2localtime(0) }'
+
++1970-01-01 02:00:00 ++ +
+mlr --tz America/Sao_Paulo -n put 'end { print sec2localtime(0) }'
+
++1969-12-31 21:00:00 ++ +
+mlr -n put 'end {
+ ENV["TZ"] = "Asia/Istanbul";
+ print sec2localtime(0);
+ print sec2localdate(0);
+ print localtime2sec("2000-01-02 03:04:05");
+ print;
+ ENV["TZ"] = "America/Sao_Paulo";
+ print sec2localtime(0);
+ print sec2localdate(0);
+ print localtime2sec("2000-01-02 03:04:05");
+}'
+
++1970-01-01 02:00:00 +1970-01-01 +946775045 + +1969-12-31 21:00:00 +1969-12-31 +946789445 ++ +Note that for local times, Miller omits the `T` and the `Z` you see in GMT times. + +We also have the +[gmt2localtime](reference-dsl-builtin-functions.md#gmt2localtime) and +[localtime2gmt](reference-dsl-builtin-functions.md#localtime2gmt) convenience functions: + +
+mlr -n put 'end {
+ ENV["TZ"] = "Asia/Istanbul";
+ print gmt2localtime("1970-01-01T00:00:00Z");
+ print localtime2gmt("1970-01-01 00:00:00");
+}'
+
++1970-01-01 02:00:00 +1969-12-31T22:00:00Z ++ +# GMT and local times with custom formats + +The to-string and from-string functions we've seen so far are low-keystroking: +with a little bit of typing you can convert datetimes to/from epoch seconds. +The minus, however, is flexibility. This is where the +[strftime](reference-dsl-builtin-functions.md#strftime), +[strptime](reference-dsl-builtin-functions.md#strptime) functions come into play. + +Notes: + +* The names `strftime` and `strptime` far predate Miller; they were chosen for familiarity. The `f` is for _format_: from epoch-seconds to human-readable string. The `p` is for _parse_: for doing the reverse. +* Even though Miller is written in Go as of Miller 6, it still preserves [C-like](https://en.wikipedia.org/wiki/C_date_and_time_functions#strftime) `strftime` and `strptime` semantics. + * For `strftime`, this is thanks to [https://github.com/lestrrat-go/strftime](https://github.com/lestrrat-go/strftime). + * For `stpftime`, this is thanks to [https://github.com/pbnjay/strptime](https://github.com/pbnjay/strptime). +* See [https://devhints.io/strftime](https://devhints.io/strftime) for sample format strings you can use. + +Some examples: + +
+mlr -n put 'end {
+ ENV["TZ"] = "Asia/Istanbul";
+ print strftime(0, "%Y-%m-%d %H:%M:%S");
+ print strftime(0, "%Y-%m-%d %H:%M:%S %Z");
+ print strftime(0, "%Y-%m-%d %H:%M:%S %z");
+ print strftime(0, "%A, %B %e, %Y");
+ print strftime(123456789, "%I:%M %p");
+}'
+
++1970-01-01 00:00:00 +1970-01-01 00:00:00 UTC +1970-01-01 00:00:00 +0000 +Thursday, January 1, 1970 +09:33 PM ++ +Unfortunately, names from `%A` and `%B` are only available in English, as an +artifact of a design choice in the Go `time` library which Miller (and its +`strftime` / `strptime` supporting packages as noted above) rely on. + +We also have +[strftimelocal](reference-dsl-builtin-functions.md#strftimelocal) and +[strptimelocal](reference-dsl-builtin-functions.md#strptimelocal): + +
+mlr -n put 'end {
+ ENV["TZ"] = "America/Anchorage";
+ print strftime_local(0, "%Y-%m-%d %H:%M:%S %Z");
+ print strftime_local(0, "%Y-%m-%d %H:%M:%S %z");
+ print strftime_local(0, "%A, %B %e, %Y");
+ print strptime_local("2020-03-01 00:00:00", "%Y-%m-%d %H:%M:%S");
+ print;
+ ENV["TZ"] = "Asia/Hong_Kong";
+ print strftime_local(0, "%Y-%m-%d %H:%M:%S %Z");
+ print strftime_local(0, "%Y-%m-%d %H:%M:%S %z");
+ print strftime_local(0, "%A, %B %e, %Y");
+ print strptime_local("2020-03-01 00:00:00", "%Y-%m-%d %H:%M:%S");
+}'
+
++1969-12-31 14:00:00 AHST +1969-12-31 14:00:00 -1000 +Wednesday, December 31, 1969 +1583053200 + +1970-01-01 08:00:00 HKT +1970-01-01 08:00:00 +0800 +Thursday, January 1, 1970 +1582992000 ++ +# Relative times + +You can get the seconds since the Miller process start using +[uptime](reference-dsl-builtin-functions.md#uptime): + + +
+color shape flag k index quantity rate u ++
+yellow triangle true 1 11 43.6498 9.8870 0.0011110305786132812 +red square true 2 15 79.2778 0.0130 0.0011241436004638672 +red circle true 3 16 13.8103 2.9010 0.0011250972747802734 +red square false 4 48 77.5542 7.4670 0.0011301040649414062 +purple triangle false 5 51 81.2290 8.5910 0.0011301040649414062 +red square false 6 64 77.1991 9.5310 0.002481222152709961 +purple triangle false 7 65 80.1405 5.8240 0.0024831295013427734 +yellow circle true 8 73 63.9785 4.2370 0.0024831295013427734 +yellow circle true 9 87 63.5058 8.3350 0.0024852752685546875 +purple square false 10 91 72.3735 8.2430 0.002485990524291992 ++ +Time-differences can be done in seconds, of course; you can also use the following if you like: + +
+mlr -F | grep hms ++
+dhms2fsec (class=time #args=1) Recovers floating-point seconds as in dhms2fsec("5d18h53m20.250000s") = 500000.250000
+dhms2sec (class=time #args=1) Recovers integer seconds as in dhms2sec("5d18h53m20s") = 500000
+fsec2dhms (class=time #args=1) Formats floating-point seconds as in fsec2dhms(500000.25) = "5d18h53m20.250000s"
+fsec2hms (class=time #args=1) Formats floating-point seconds as in fsec2hms(5000.25) = "01:23:20.250000"
+hms2fsec (class=time #args=1) Recovers floating-point seconds as in hms2fsec("01:23:20.250000") = 5000.250000
+hms2sec (class=time #args=1) Recovers integer seconds as in hms2sec("01:23:20") = 5000
+sec2dhms (class=time #args=1) Formats integer seconds as in sec2dhms(500000) = "5d18h53m20s"
+sec2hms (class=time #args=1) Formats integer seconds as in sec2hms(5000) = "01:23:20"
+
+
+# References
+
+* List of formatting characters for `strftime` and `strptime`: [https://devhints.io/strftime](https://devhints.io/strftime)
+* List of valid timezone names: [https://en.wikipedia.org/wiki/List_of_tz_database_time_zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)
diff --git a/docs6/src/reference-dsl-time.md.in b/docs6/src/reference-dsl-time.md.in
new file mode 100644
index 000000000..4d1070ee2
--- /dev/null
+++ b/docs6/src/reference-dsl-time.md.in
@@ -0,0 +1,226 @@
+# DSL datetime/timezone functions
+
+Dates/times are not a separate data type; Miller uses ints for
+[seconds since the epoch](https://en.wikipedia.org/wiki/Unix_time) and strings for formatted
+date/times. In this page we take a look at what some of the various options are
+for processing datetimes andd timezones in your data.
+
+See also the [section on time-related
+functions](reference-dsl-builtin-functions/index.html#time-functions) for
+information auto-generated from Miller's online-help strings.
+
+# Epoch seconds
+
+[Seconds since the epoch](https://en.wikipedia.org/wiki/Unix_time), or _Unix
+Time_, is seconds (positive, zero, or negative) since midnight January 1 1970
+UTC. This representation has several advantages, and is quite common in the
+computing world.
+
+Since this is a [number](reference-main-arithmetic.md) in Miller -- 64-bit
+signed integer or double-precision floating-point -- this can represent dates
+billions of years into the past or future without worry of overflow. (There is
+no [year-2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) here.)
+Being numbers, epoch-seconds are easy to store in databases, communicate over
+networks in binary format, etc. Another benefit of epoch-seconds is that
+they're independent of timezone or daylight-savings time.
+
+One minus is that, being just numbers, they're not particularly human-readable
+-- hence the to-string and from-string functions described below. Another
+caveat (not really a minus) is that _epoch milliseconds_ are common in some
+contexts, particulary JavaScript. If you every see a timestamp for the year
+49,000-something -- probablhy someone is treating epoch-milliseconds as
+epoch-seconds.
+
+GENMD_RUN_COMMAND
+mlr -n put 'end {
+ print sec2gmt(1500000000);
+ print sec2gmt(1500000000000);
+}'
+GENMD_EOF
+
+You can get the current system time, as epoch-seconds, using the
+[systime](reference-dsl-builtin-functions.md#systime) DSL function:
+
+GENMD_CARDIFY_HIGHLIGHT_ONE
+mlr --c2p --from example.csv put '$t = systime()'
+color shape flag k index quantity rate t
+yellow triangle true 1 11 43.6498 9.8870 1634784588.045347
+red square true 2 15 79.2778 0.0130 1634784588.045385
+red circle true 3 16 13.8103 2.9010 1634784588.045386
+red square false 4 48 77.5542 7.4670 1634784588.045393
+purple triangle false 5 51 81.2290 8.5910 1634784588.045394
+red square false 6 64 77.1991 9.5310 1634784588.045417
+purple triangle false 7 65 80.1405 5.8240 1634784588.045418
+yellow circle true 8 73 63.9785 4.2370 1634784588.045419
+yellow circle true 9 87 63.5058 8.3350 1634784588.045421
+purple square false 10 91 72.3735 8.2430 1634784588.045422
+GENMD_EOF
+
+The [systimeint](reference-dsl-builtin-functions.md#systimeint) DSL functions
+is nothing more than a keystroke-saver for `int(systime())`.
+
+# UTC times with standard format
+
+One way to make epoch-seconds human-readable, while maintaining some of their
+benefits such as being independent of timezone and daylight savings, is to use
+the [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) format. This was the
+first (and initially only) human-readable date/time format supported by Miller
+going all the way back to Miller 1.0.0.
+
+You can get these from epoch-seconds using the
+[sec2gmt](reference-dsl-builtin-functions.md#sec2gmt) DSL function.
+(Note that the terms _UTC_ and _GMT_ are used interchangeably in Miller.)
+We also have [sec2gmtdate](reference-dsl-builtin-functions.md#sec2gmtdate) DSL function.
+
+GENMD_RUN_COMMAND
+mlr -n put 'end {
+ print sec2gmt(0);
+ print sec2gmt(1234567890.123);
+ print sec2gmt(-1234567890.123);
+ print;
+ print sec2gmtdate(0);
+ print sec2gmtdate(1234567890.123);
+ print sec2gmtdate(-1234567890.123);
+}'
+GENMD_EOF
+
+# Local times with standard format; specifying timezones
+
+You can use similar formatting for dates in your preferred timezone, not just UTC/GMT.
+We have the
+[sec2localtime](reference-dsl-builtin-functions.md#sec2localtime),
+[sec2localdate](reference-dsl-builtin-functions.md#sec2localdate), and
+[localtime2sec](reference-dsl-builtin-functions.md#localtime2sec) DSL functions.
+
+You can specify the timezone using any of the following:
+
+* An environment variable, e.g. `export TZ=Asia/Istanbul` at your system prompt (`set TZ=Asia/Istanbul` in Windows)
+* Using the `--tz` flag. This sets the `TZ` environment variable, but only internally to the `mlr` process
+* Within a DSL expression, you can assign to `ENV["TZ"]`.
+
+Regardless, if you specifiy an invalid timezone, you'll be clearly notified:
+
+GENMD_RUN_COMMAND_TOLERATING_ERROR
+mlr --from example.csv --tz This/Is/A/Typo cat
+GENMD_EOF
+
+GENMD_RUN_COMMAND
+export TZ=Asia/Istanbul
+mlr -n put 'end { print sec2localtime(0) }'
+GENMD_EOF
+
+GENMD_RUN_COMMAND
+mlr --tz America/Sao_Paulo -n put 'end { print sec2localtime(0) }'
+GENMD_EOF
+
+GENMD_RUN_COMMAND
+mlr -n put 'end {
+ ENV["TZ"] = "Asia/Istanbul";
+ print sec2localtime(0);
+ print sec2localdate(0);
+ print localtime2sec("2000-01-02 03:04:05");
+ print;
+ ENV["TZ"] = "America/Sao_Paulo";
+ print sec2localtime(0);
+ print sec2localdate(0);
+ print localtime2sec("2000-01-02 03:04:05");
+}'
+GENMD_EOF
+
+Note that for local times, Miller omits the `T` and the `Z` you see in GMT times.
+
+We also have the
+[gmt2localtime](reference-dsl-builtin-functions.md#gmt2localtime) and
+[localtime2gmt](reference-dsl-builtin-functions.md#localtime2gmt) convenience functions:
+
+GENMD_RUN_COMMAND
+mlr -n put 'end {
+ ENV["TZ"] = "Asia/Istanbul";
+ print gmt2localtime("1970-01-01T00:00:00Z");
+ print localtime2gmt("1970-01-01 00:00:00");
+}'
+GENMD_EOF
+
+# GMT and local times with custom formats
+
+The to-string and from-string functions we've seen so far are low-keystroking:
+with a little bit of typing you can convert datetimes to/from epoch seconds.
+The minus, however, is flexibility. This is where the
+[strftime](reference-dsl-builtin-functions.md#strftime),
+[strptime](reference-dsl-builtin-functions.md#strptime) functions come into play.
+
+Notes:
+
+* The names `strftime` and `strptime` far predate Miller; they were chosen for familiarity. The `f` is for _format_: from epoch-seconds to human-readable string. The `p` is for _parse_: for doing the reverse.
+* Even though Miller is written in Go as of Miller 6, it still preserves [C-like](https://en.wikipedia.org/wiki/C_date_and_time_functions#strftime) `strftime` and `strptime` semantics.
+ * For `strftime`, this is thanks to [https://github.com/lestrrat-go/strftime](https://github.com/lestrrat-go/strftime).
+ * For `stpftime`, this is thanks to [https://github.com/pbnjay/strptime](https://github.com/pbnjay/strptime).
+* See [https://devhints.io/strftime](https://devhints.io/strftime) for sample format strings you can use.
+
+Some examples:
+
+GENMD_RUN_COMMAND
+mlr -n put 'end {
+ ENV["TZ"] = "Asia/Istanbul";
+ print strftime(0, "%Y-%m-%d %H:%M:%S");
+ print strftime(0, "%Y-%m-%d %H:%M:%S %Z");
+ print strftime(0, "%Y-%m-%d %H:%M:%S %z");
+ print strftime(0, "%A, %B %e, %Y");
+ print strftime(123456789, "%I:%M %p");
+}'
+GENMD_EOF
+
+Unfortunately, names from `%A` and `%B` are only available in English, as an
+artifact of a design choice in the Go `time` library which Miller (and its
+`strftime` / `strptime` supporting packages as noted above) rely on.
+
+We also have
+[strftimelocal](reference-dsl-builtin-functions.md#strftimelocal) and
+[strptimelocal](reference-dsl-builtin-functions.md#strptimelocal):
+
+GENMD_RUN_COMMAND
+mlr -n put 'end {
+ ENV["TZ"] = "America/Anchorage";
+ print strftime_local(0, "%Y-%m-%d %H:%M:%S %Z");
+ print strftime_local(0, "%Y-%m-%d %H:%M:%S %z");
+ print strftime_local(0, "%A, %B %e, %Y");
+ print strptime_local("2020-03-01 00:00:00", "%Y-%m-%d %H:%M:%S");
+ print;
+ ENV["TZ"] = "Asia/Hong_Kong";
+ print strftime_local(0, "%Y-%m-%d %H:%M:%S %Z");
+ print strftime_local(0, "%Y-%m-%d %H:%M:%S %z");
+ print strftime_local(0, "%A, %B %e, %Y");
+ print strptime_local("2020-03-01 00:00:00", "%Y-%m-%d %H:%M:%S");
+}'
+GENMD_EOF
+
+# Relative times
+
+You can get the seconds since the Miller process start using
+[uptime](reference-dsl-builtin-functions.md#uptime):
+
+
+GENMD_CARDIFY_HIGHLIGHT_ONE
+color shape flag k index quantity rate u
+yellow triangle true 1 11 43.6498 9.8870 0.0011110305786132812
+red square true 2 15 79.2778 0.0130 0.0011241436004638672
+red circle true 3 16 13.8103 2.9010 0.0011250972747802734
+red square false 4 48 77.5542 7.4670 0.0011301040649414062
+purple triangle false 5 51 81.2290 8.5910 0.0011301040649414062
+red square false 6 64 77.1991 9.5310 0.002481222152709961
+purple triangle false 7 65 80.1405 5.8240 0.0024831295013427734
+yellow circle true 8 73 63.9785 4.2370 0.0024831295013427734
+yellow circle true 9 87 63.5058 8.3350 0.0024852752685546875
+purple square false 10 91 72.3735 8.2430 0.002485990524291992
+GENMD_EOF
+
+Time-differences can be done in seconds, of course; you can also use the following if you like:
+
+GENMD_RUN_COMMAND
+mlr -F | grep hms
+GENMD_EOF
+
+# References
+
+* List of formatting characters for `strftime` and `strptime`: [https://devhints.io/strftime](https://devhints.io/strftime)
+* List of valid timezone names: [https://en.wikipedia.org/wiki/List_of_tz_database_time_zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)
diff --git a/docs6/src/reference-main-data-types.md b/docs6/src/reference-main-data-types.md
index 80d77e82d..1bb0cc7af 100644
--- a/docs6/src/reference-main-data-types.md
+++ b/docs6/src/reference-main-data-types.md
@@ -23,6 +23,7 @@ Miller's types are:
* Scalars:
* **string**: such as `"abcdefg"`, supporting concatenation, one-up indexing and slicing, and [library functions](reference-dsl-builtin-functions.md#string-functions). See the pages on [strings](reference-main-strings.md) and [regular expressions](reference-main-regular-expressions.md).
* **float** and **int**: such as `1.2` and `3`: double-precision and 64-bit signed, respectively. See the section on [arithmetic operators and math-related library functions](reference-dsl-builtin-functions.md#math-functions) as well as the [Arithmetic](reference-main-arithmetic.md) page.
+ * dates/times are not a separate data type; Miller uses ints for [seconds since the epoch](https://en.wikipedia.org/wiki/Unix_time) and strings for formatted date/times. See the [DSL datetime/timezone functions page](reference-dsl-time.md) for more information.
* **boolean**: literals `true` and `false`; results of `==`, `<`, `>`, etc. See the section on [boolean operators](reference-dsl-builtin-functions.md#boolean-functions).
* Collections:
* **map**: such as `{"a":1,"b":[2,3,4]}`, supporting key-indexing, preservation of insertion order, [library functions](reference-dsl-builtin-functions.md#collections-functions), etc. See the [Maps](reference-main-maps.md) page.
diff --git a/docs6/src/reference-main-data-types.md.in b/docs6/src/reference-main-data-types.md.in
index 2dcef0f87..0cbfc949e 100644
--- a/docs6/src/reference-main-data-types.md.in
+++ b/docs6/src/reference-main-data-types.md.in
@@ -7,6 +7,7 @@ Miller's types are:
* Scalars:
* **string**: such as `"abcdefg"`, supporting concatenation, one-up indexing and slicing, and [library functions](reference-dsl-builtin-functions.md#string-functions). See the pages on [strings](reference-main-strings.md) and [regular expressions](reference-main-regular-expressions.md).
* **float** and **int**: such as `1.2` and `3`: double-precision and 64-bit signed, respectively. See the section on [arithmetic operators and math-related library functions](reference-dsl-builtin-functions.md#math-functions) as well as the [Arithmetic](reference-main-arithmetic.md) page.
+ * dates/times are not a separate data type; Miller uses ints for [seconds since the epoch](https://en.wikipedia.org/wiki/Unix_time) and strings for formatted date/times. See the [DSL datetime/timezone functions page](reference-dsl-time.md) for more information.
* **boolean**: literals `true` and `false`; results of `==`, `<`, `>`, etc. See the section on [boolean operators](reference-dsl-builtin-functions.md#boolean-functions).
* Collections:
* **map**: such as `{"a":1,"b":[2,3,4]}`, supporting key-indexing, preservation of insertion order, [library functions](reference-dsl-builtin-functions.md#collections-functions), etc. See the [Maps](reference-main-maps.md) page.
diff --git a/go/todo.txt b/go/todo.txt
index a89404134..b4c6ca789 100644
--- a/go/todo.txt
+++ b/go/todo.txt
@@ -56,6 +56,8 @@ d pre-release:
o draft release w/ m6 binaries YYYYMMDD -- ?
o gha download steps clearer
+* wut h1 spacing before/after ...
+
----------------------------------------------------------------
LOCALTIME
@@ -74,44 +76,9 @@ LOCALTIME
* new webdoc separate PR
- incl https://github.com/johnkerl/miller/issues/331
-* ENV["TZ"] update:
- o --tz is a setenv & is treated the same. also ENV["TZ"]
- o no explicit tz arg @ dsl functions, sorry ...
- o now maybe simplify the RTs ...
- o at very least, at a multi-tz case
- o sec2gmt sec2localtime
- sec2gmtdate sec2localdate
- strftime strftime_local
- o gmt2sec localtime2sec
- strptime strptime_local
- o gmt2localtime localtime2gmt
- o note in new webdoc
- mlr> sec2localtime(0)
- "1969-12-31 19:00:00"
- mlr> ENV["TZ"]=""
- mlr> sec2localtime(0)
- "1970-01-01 00:00:00"
- mlr> ENV["TZ"]="GMT"
- mlr> sec2localtime(0)
- "1970-01-01 00:00:00"
- mlr> ENV["TZ"]="Asia/Istanbul"
- mlr> sec2localtime(0)
- "1970-01-01 02:00:00"
- mlr> ENV["TZ"]="America/Sao_Paulo"
- mlr> sec2localtime(0)
- "1969-12-31 21:00:00"
- o ref:
- https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
- http://www.iana.org/time-zones
- https://en.wikipedia.org/wiki/Tz_database
- https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
-
* https://github.com/johnkerl/miller/issues/332
o localtime2gmt and gmt2localtime
--tz
- k maybe health-check with `location, err := time.LoadLocation("America/Los_Angeles")` -- ?
- ? make this this applies to all datetimes that don't include a time zone
- ? also make sure that, absent this, all zoneless datatimes are interpreted in that timezone
----------------------------------------------------------------
398