Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feedback on Dates and Times in Section 11 #22

Open
mattjohnsonpint opened this issue Jul 20, 2016 · 4 comments
Open

Feedback on Dates and Times in Section 11 #22

mattjohnsonpint opened this issue Jul 20, 2016 · 4 comments

Comments

@mattjohnsonpint
Copy link
Contributor

mattjohnsonpint commented Jul 20, 2016

Please review the following constructive criticism with regard to the date and time guidelines in section 11.

Iso8601Literal is poorly defined

  • ECMAScript is not the normative reference for ISO8601, and actually gets parts of it wrong. For details, refer to my blog on this subject, and to Date Time String Format: default time zone difference from ES5 not web-compatible tc39/ecma262#87 and Normative: Date.parse treats date-only no offset as UTC tc39/ecma262#138.
  • The preferred reference should be RFC 3339. The W3C's Date and Time Formats note is also applicable.
  • The guidance misses a very important consideration, which is that date-time forms should be fully qualified with either Z or a numeric offset +/-HH:MM so that they represent a distinct point in time:
    • "2016-07-16T08:23:45Z" is a specific point in Coordinated Universal Time (UTC).
    • "2016-07-16T01:23:45-07:00" is the same point in time with a particular time zone offset.
    • "2016-07-16T01:23:45" is not a specific point in time. It could be interpreted differently depending on time zones. While this is type of data may be useful within an application, it has very little meaning in an API and should generally be discouraged as an interchange format.
  • The guidance misses another very important consideration, which is that date-only forms should not carry any time element or time zone offset.
    • "2016-07-16" is a valid date. Date-only values should always be passed like this.
    • "2016-07-16T00:00:00Z" is not a date. It's a date-time at midnight UTC. The equivalent date value may be quite different when adjusted to the local time zone. This is a commonly encountered anti-pattern, and should be actively discouraged.
    • "2016-07-16T00:00:00" is also not a date. It's a date-time at midnight local time. The main problem here is that not every local date has a midnight (due to daylight saving time spring-forward gaps). For example, "2016-10-16T00:00:00" does not exist in most of Brazil. Given this value, and this time zone context, some implementations may skip forward to 1:00, some may skip backward to 23:00 the prior day, and some may throw an exception.

To address all of these, the guidance should recommend using the date-time and full-date formats defined in RFC 3339 § 5.6.

StructuredDateLiteral is not good advice

  • The list of DateKind value codes appears to be invented here. I know of no JSON library that will create or read value in this split two-state form. You would have to create your own intermediate objects, then either have a long case-statement to handle all the different kinds, or limit yourself to one particular kind. Indeed, the guidance talks about how different clients would need to understand the kind of the server. This requirement defeats the purpose of having an interchange format to begin with. In other words, it's no more helpful to have a kind property that tells you what format to expect in the value property than it would be to describe the custom format in the API's documentation.
  • The list is by no means complete of all the different custom formats that have been used for date and time values. As soon as you start picking and choosing from which custom formats you want to honor, you open it up for others to add more. Notably absent is RFC822/2822 such as used in HTTP headers, and also the abhorant but widespread ASP.NET JSON date format. (See Scott Hanselman's blog post, On the nightmare that is JSON Dates. Plus, JSON.NET and ASP.NET Web API.) I'm not advocating for either of these, but if you continue down this route - eventually someone will. There are many others also.
  • Some of the formats in the list are completely inappropriate for the web.
    • The "O" format is being used for OLE Automation Dates - this format uses an ambiguous local time scale, while most of the others use UTC. Also, some implementations base it from 1900-01-01 or 1899-12-31, instead of 1899-12-30, and there is extra work to account for negative values. This is something that should be only handled directly when interfacing to/from OLE values - such as by calling DateTime.FromOADate or DateTime.ToOADate in .NET. The OADate values themselves should never be put into a web API.
    • The "X" format honors the Excel 1900 leap year bug - really? This should never leak out of Excel. Putting it in an API would be a horrible thing to do.
  • This document is supposed to be about best practices - guidelines that REST APIs should follow. Therefore, I highly recommend you remove this section entirely. Formats that are specific to a particular language should not be used in a language-neutral setting. The only advice should be to use the common interchange formats described by ISO8601.

Misc other items

  • The info on Durations in 11.4 is good, but it would also be good to mention that one should be careful to avoid specifying Months or Years unless they actually mean the variable unit of time associated with a calendar month or a calendar year. In other words, do not assume all months are 30 days, or all years are 365 days.
  • The info on Intervals in 11.5 is acceptable, but it's equally acceptable to simply place each value into a separate JSON property. This is more common in practice, as there are few parsers that natively recognize the interval format. In other words, { "interval" : "2007-03-01T13:00:00Z/2008-05-11T15:30:00Z" } is less commonly used than { "start" : "2007-03-01T13:00:00Z", "end" : "2008-05-11T15:30:00Z" }. Though either are technically acceptable, the latter is usually prefered because it's easier to work with.
    • The same applies for Recurring Intervals in 11.6. Also note that this format is much less commonly encountered in web APIs than it is in scheduling systems. I'm not sure how much value it has in this document as a recommendation for REST APIs.

Thanks.

@garethj-msft
Copy link
Member

Matt, thank you very much for the detailed feedback.

@maggiepint
Copy link

I'll generally just agree with Matt here, but would add the following:

Informally, a DateValue is either an ISO 8601-formatted string or a JSON object containing two properties named kind and value that together define a point in time.

This text assumes that all date values exchanged by a REST API are defined by a point in time. This assumption is incorrect and does not hold water in the real world.

For instance, one might want to express this information in an API:

All Microsoft store locations open at 05:00 in the morning on Black Friday in 2016.

This is a datetime value, that would be expressed by the ISO8601 standard as 2016-11-25T05:00:00.00, where this is interpreted as local time to the store. It is not any single point on the global timeline.

You may also encounter time-only situations like

All Microsoft store locations open at 11:00 on Saturdays

Again, there is no reference to a point in time, and this should be interpreted as time local to the store.
RFC 3339 would specify this as partial-time in the format 11:00:00.

This documentation should explicitly state that absent an offset values shall be interpreted as local time (which may vary based on the context of the problem domain). While ISO8601 and ECMAScript already say this, most people won't go look it up, so if this is best practice documentation, best to put it in. It should also be noted that these formats should only be used if you mean local time. If you mean time that represents a point on the global timeline, ISO8601 with offset should almost universally be used.

On that note, I will echo that StructuredDateLiteral is not good advice. If these formats had to be handled, I guess it would be a way to do it. That said, this appears to be best practice documentation. The best practice would be to keep formats like that inside your own ecosystem, and convert to ISO8601 for data transfer purposes. Anything else would be in conflict with established internet norms.

Happy to think harder about the local time documentation and make a pull if you would like one.

@mattjohnsonpint
Copy link
Contributor Author

mattjohnsonpint commented Jul 20, 2016

Yes, I'll agree with Maggie's statements (thank you). The partial-time format is indeed worth adding.

On the Black Friday example, I suppose that is indeed a valid value - and one might get it by using a .NET DateTime having DateTimeKind.Unspecified. However - in the vast majority of use cases I've encountered - the value is usually intended to describing a specific moment in time, rather than a floating value. I'll suggest then that the guidance say something like the following:

A date+time value MUST include a time zone offset in the form +/-HH:MM (or Z for UTC) if it is intended to represent a specific instant in time. A date+time value without an offset specified is assumed to be in some local time, or could be interpreted as a floating time value, not belonging to any specific time zone.

Does that make sense?

@mattjohnsonpint
Copy link
Contributor Author

@garethj-msft - No problem, glad to help. I'm going to ask some of the other @mspnp guys to take a look at the other parts of the guidelines also. Date/time just happens to be my thing. 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants