qt4cg / qtspecs

QT4 specifications
https://qt4cg.org/
Other
28 stars 15 forks source link

New function: System’s default time zone for arbitrary date/time values. #1539

Open ChristianGruen opened 6 days ago

ChristianGruen commented 6 days ago

It is not easy to find out the correct timezone for a given UTC xs:dateTime in the current region. We have fn:implicit-timezone, but it only refers to the current date and time.

The following code works for at least BaseX and Saxon; it applies the system’s default time zone to a given xs:dateTime item:

let $dtm := xs:dateTime('2024-07-01T01:01:01Z')
let $ms := xs:integer(($dtm - xs:dateTime('1970-01-01T00:00:00Z')) div xs:dayTimeDuration('PT0.001S'))
let $tz := xs:dayTimeDuration('PT' ||
  Q{java:java.time.ZonedDateTime}ofInstant(
    Q{java:java.time.Instant}ofEpochMilli($ms),
    Q{java:java.time.ZoneId}systemDefault()
  )
  => Q{java:java.time.ZonedDateTime}getOffset()
  => Q{java:java.time.ZoneOffset}getTotalSeconds()|| 'S')
return adjust-dateTime-to-timezone($dtm, $tz)

It returns 2024-07-01T03:01:01+02:00 (MESZ) on systems located in Leipzig and nearby cities.

We could either introduce a function that

  1. returns an xs:dayTimeDuration timezone for a given xs:dateTime item (with the system’s default time zone applied), or
  2. converts an xs:dateTime item to the system’s default time zone at the given date/time.

Suggestions for good names are welcome.

See also https://xmlcom.slack.com/archives/C01GVC3JLHE/p1730216267200449:

ndw commented 5 days ago

Just to make sure I understand the intent, and why this is not just:

adjust-dateTime-to-timezone(xs:dateTime('2024-07-01T01:01:01Z'), implicit-timezone())

The problem is that July 1 is in summer time and now (on 30 October, 2024), the implicit timezone is returning the offset for winter time. Is that right?

I think I prefer the former, fn:implicit-timezone-for-dateTime. But let's just say this is an interesting problem: https://norman.walsh.name/2013/05/30/timezones

ChristianGruen commented 5 days ago

The problem is that July 1 is in summer time and now (on 30 October, 2024), the implicit timezone is returning the offset for winter time. Is that right?

Exactly. A trivial use case is if you want to list files in a directory (with the File Module and file:list/file:last-modified) with intuitive timestamps:

2020/12/01  14:00  created-at-13:00:00Z-in-leipzig-in-winter.txt
2020/06/01  15:00  created-at-13:00:00Z-in-leipzig-in-summer.txt

I think I prefer the former, fn:implicit-timezone-for-dateTime. But let's just say this is an interesting problem: https://norman.walsh.name/2013/05/30/timezones

Thanks for the link; I’ll check the referenced source code.

michaelhkay commented 5 days ago

If I understand correctly, the intent is to answer the question "given my current location (Leipzig), what will the local time be at some point in the future or past, e.g. 2010-09-30T24:00:00Z". Obviously this can only be answered with knowledge of the current location and a database of civil time zone changes applicable to that location.

If we're going to provide an answer to that question then it seems logical to me to go one step further and answer the question: "for any specified location (e.g. Africa/Cairo), what will the local time be at some point in the future or past, e.g. 2010-09-30T24:00:00Z".

In fact I think we already have this capability in format-dateTime($dt, place="de") but of course it shouldn't really be part of formatting.

ndw commented 5 days ago

I had the same thought. In fact, I downloaded the timezone database to remind myself how hard it would be to just implement it natively. But I've persuaded myself that such a task is not on the first couple dozen pages of my todo list. Fun though it would be.

Allowing the user to select a location opens up a lot of potential issues. But first, I think that place in format-dateTime is a completely orthogonal dimension: given this date time, please format it according to German convensions, or Swiss conventions, or American conventions. Saying place="us" is competely unsatisfactory for determining the time zone.

Maybe, maybe, the date time APIs in modern computer languages are all so dependent on the Olson timezone database that we could get interoperability for "Africa/Cairo" but I'm not certain of that. What does JavaScript provide? What does Python provide?

If we're interested in tackling the question more generally, we probably want a few new functions maybe in a new namespace.

I think @ChristianGruen 's proposal to limit the functionality to the current implicit timezone is probably a useful simplification that still satisfies a lot of use cases.

But I'm on the fence. I think it's a pretty short step for the user to go from When was 2024-07-01T01:01:01Z "here" to When was 2024-07-01T01:01:01Z "in Paris".

michaelhkay commented 5 days ago

But first, I think that place in format-dateTime is a completely orthogonal dimension: given this date time, please format it according to German convensions, or Swiss conventions, or American conventions. Saying place="us" is competely unsatisfactory for determining the time zone.

No, $place is explicitly documented as referring to the place associated with the date/time you are talking about, not the place where the reader/user is located. And yes, place="us" is useless, which is why we explicitly encourage implementations to recognise place="America/Chicago".

I think most mainstream platforms have libraries that use the Olsen timezone naming conventions.

ndw commented 5 days ago

My bad. I didn't read far enough. Why on Earth (or on any inhabited planet you care to name) is that in the format functions?

michaelhkay commented 5 days ago

If you really want the answer, I suspect it is that the person who argued most strongly that the functionality was needed was Anders Berglund, and the formatting functions were his baby. That's how committees work.

ndw commented 5 days ago

I am aware. But that's just weird. Anyway, implementations clearly have the necessary functionality available, so to pull this comment thread back on track, ... would this work?

fn:timezone-from-name($zone-id as xs:string, $timestamp as xs:dateTimeStamp?)

Returns the timezone offset for the named location at the specified time stamp. If the timestamp is not provided, the current dateTime in the implicit timezone is used.

ndw commented 5 days ago

Maybe fn:timezone-from-zone-id would be a better name.

michaelhkay commented 5 days ago

I think the basic signature works. "from-name" suggests we're dealing with timezone names like CET which we're not. I'm tempted by fn:timezone-for-place-and-time. Or perhaps fn:local-timezone. Or fn:local-timezone-offset.