glacials / whatsinstandard

a Magic: The Gathering format reference
https://whatsinstandard.com
MIT License
130 stars 34 forks source link

Add time zone to exit and enter dates. RFC3339 #255

Closed Enviy closed 1 year ago

Enviy commented 1 year ago

The current format for set enterDate and exitDate follow the pattern "2016-09-30T00:00:00.000". This pattern does not support a timezone so it can be difficult to determine if it's the current day locally when executing the validation check.

My suggestion is to migrate this format to the RFC3339 pattern of "2006-01-02T15:04:05Z07:00" which does support a time zone.

glacials commented 1 year ago

Thanks for pointing this out! We purposefully removed the time zone in #75 because AFAIK rotation does not have a canonical time zone, but happens on the first moment of the calendar date in whatever time zone you're playing in. This didn't seem like a big deal to get right before, but #75 pointed out a pretty ugly UX side effect of specifying time zone.

At minimum the issue I see here is that our API's schema declares we use RFC 3339 (which also reflects in our API docs), but RFC 3339 does not support timezoneless timestamps. What we are actually returning are just ISO 8601 timestamps.

So I'm inclined to keep the behavior and update the docs, however I'm curious if you have a use case that would be violated by that, in case there is a compelling reason to specify a time zone.

Enviy commented 1 year ago

Ah, alright. My initial concern with the timezoneless dateTime was that I was worried about one calendar day in say the US not being the same for someone in another place like Hong Kong. But if releases go live on a localized calendar day the yeah that works out, we can just use the calendar date version of the dateTime value.

I think keeping the current behavior and updating the documentation works. I ended up spitting the extra milliseconds off and swapping the "T" character with a space to support Go time.Time parsing. https://github.com/Enviy/mtg-sdk-go/blob/main/standard.go

Thanks!

glacials commented 1 year ago

Thanks for explaining! I've updated the docs to indicate ISO 8601.

In Go, I suggest using time.ParseInLocation so you don't fall prey to the same bug from #75. Since you are parsing the times implicitly as UTC and then calling .Local(), what was 2023-02-19T00:00:00 can become e.g. 2023-02-18T16:00:00 if your local time is UTC-8.

I think you can also avoid the other hijinks by adjusting your format string, and keeping in mind this behavior about how Go parses times:

the input may contain a fractional second field immediately after the seconds field, even if the layout does not signify its presence

Something like:

place := "America/Los_Angeles" // Or whatever time zone the end user will be in
location, err := time.LoadLocation(place)
if err != nil {
  // ...
}

format := "2006-01-02T15:04:05"
t, err := time.ParseInLocation(format, enter, location)
if err != nil {
  // ...
}

// t now represents midnight local time for the enter date