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

Format %Z as ±HH:MM instead of ±HHMM? #35

Closed
jharris4 opened this issue Sep 20, 2017 · 6 comments
Closed

Format %Z as ±HH:MM instead of ±HHMM? #35

jharris4 opened this issue Sep 20, 2017 · 6 comments

Comments

@jharris4
Copy link

jharris4 commented Sep 20, 2017

I have an application that's parsing date strings with a format that includes %Z like in the example below:

import { utcFormat, utcParse } from 'd3-time-format';

const dateFormat = '%Y-%m-%dT%H:%M:%S%Z';
const dateParser = utcParse(dateFormat);
const dateFormatter = utcFormat(dateFormat);

let dateString = '2017-09-15T06:00:00+00:00';
let dateObject = new Date(dateString);
let parsedDate = dateParser(dateString);

let formattedDateString = dateFormatter(parsedDate);

let newDateObject = new Date(formattedDateString);
let newParsedDate = dateParser(formattedDateString);

The formattedDateString is equal to 2017-09-15T06:00:00+0000 as expected given the return value of the formatZone function (https://github.com/d3/d3-time-format/blob/master/src/locale.js#L523)

function formatUTCZone() {
  return "+0000";
}

The trouble is that in the above code newDateObject has the expected Date value in Chrome/Firefox/Edge, but is a Date which is flagged as an invalid date in Safari or IE11.

I need to pass date strings to a library that then converts them to Date objects, and I'm using utcHour from d3-time to generate some of the date strings. Given those constraints I was able to work around this problem using the following code instead of just calling dateFormatter(date) directly:

let formatAndFixZone = date => dateFormatter(date).replace('+0000', '+00:00'); // Safari/IE11 fix for default d3 timezone formatting.

TLDR; In Safari and IE11 the Date constructor requires the timezones to be formatted with a : (colon) to be able to parse from date strings.

I get that this is probably a minor concern for d3, since utcParse exists (and local variants as well), but I was curious to know if there was a strong reason for not changing the default formatting to format time zones as +00:00 instead of +0000. This would allow ISO 8601 date strings to be generated with d3-time-format in a way that could be natively parsed in all browsers.

@mbostock
Copy link
Member

This is the expected behavior when formatting the %Z directive. (Parsing %Z is more flexible: we support ±HH, ±HH:MM, ±HHMM and the literal Z.)

But, it might be possible to extend the %Z directive to include a modifier, similar to how %-d disables the default zero padding. Not entirely sure how that would work since the padding modifiers are applied generically to all directives, and this wouldn’t be a padding modifier per se (unless we want to arbitrarily overload the meaning of the padding modifier in the context of formatting the time zone offset, which is probably inadvisable).

Or, another possibility would be to introduce another directive, like %z, for ±HH:MM.

Or, we could just change the behavior of %Z. I think that would probably also be inadvisable for backwards-compatibility reasons, though perhaps it could be done with a major version bump.

@mbostock mbostock changed the title Date formatted with %Z results in invalid date when parsed with new Date() in Safari/IE11 Format %Z as ±HH:MM instead of ±HHMM? Sep 20, 2017
@jharris4
Copy link
Author

Thanks for taking the time to look into this somewhat obscure issue! :-)

I had indeed noticed PR #4 which made the date parsing looser for timezone formatting

You have a good point that changing the behavior of %Z could be inadvisable for backward compatibility reasons.

Using the padding modifiers (0, _, -) is an interesting option, but it is indeed hard to see how to map those sensibly to the 3 timezone formats (±HH, ±HHMM, ±HH:MM) even if the number of modifiers to formats does conveniently line up.

There's also the fact that there isn't currently a way to choose whether Z should be used whenever possible in place of any occurrence of ±00, ±0000 or ±00:00...

I'd be inclined to look at some type of syntax for the format string like %2Z or %4Z or %4:Z, and maybe use something like the lower case z to parallel that, but with greedy attempts to use Z for the timezone whenever the offset from UTC is 0...

I'm not sure how difficult it would be to implement parameterized variants of %Z like this (and of course the padding modifiers would need to be handled).

I suppose that if people see some value in it then I could try to find the time to make a PR.

@Sionicmon
Copy link

Hi everyone,
is it possible that you can help me?

I have a function like this:
var parseDate = d3.time.format("%Y-%m-%dT%H:%M:%S.%L%Z").parse;

But when i call:
parseDate("2018-03-20T21:02:10.981+01:00")
ist always return null. But why?

When i change the format to "%Y-%m-%dT%H:%M:%S.%L+01:00" it works, but i have timestamps with +01:00 and +02:00 so that wouldnt work out for me.

Can you please say me why %Z is not parsing the +01:00 in my example?

@mbostock
Copy link
Member

@Sionicmon You are using an old version of D3. The relaxed %Z parser was added in D3 4.0 / d3-time-format 1.0. Here is an example:

https://beta.observablehq.com/d/8734448fe49bfb0e

@Sionicmon
Copy link

@mbostock Thanks for your help!

@mbostock
Copy link
Member

I believe this is covered by #6.

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

No branches or pull requests

3 participants