Reputation: 295
I am using following ISO8601 format:
YYYY-MM-DDThh:mm:ssZ
And I used OffsetDateTime.parse()
to parse this format. I was able to parse date-time by passing t
(instead of T
) and z
(instead of Z
) here.
So can anyone tell if it is allowed in ISO8601 or is it missed only in parsing logic?
Upvotes: 7
Views: 1734
Reputation: 74277
Just for the record, ISO 8601:2004 Data elements and interchange formats — Information interchange —Representation of dates and times, page 11 says (and I quote):
NOTE 1 In date and time representations lower case characters may be used when upper case letters are not available.
The designators to which this would apply are enumerated on page 11, ibid:
P
: the duration designator, the use of P
being based on the "historical" use of the term "period" for duration)R
: the recurring time interval designatorT
: the time designatorW
: the week designatorZ
: the UTC designator (the use of Z
being based on the common military, marine, and aviation usage of calling UTC "Zulu time").Upvotes: 3
Reputation: 86296
While I don’t know about ISO 8601 on this point, it is documented that Java’s one-arg OffsetDateTime.parse(CharSequence)
allows both upper and lower case T
and Z
.
The documentation says:
The string must represent a valid date-time and is parsed using
DateTimeFormatter.ISO_OFFSET_DATE_TIME
.
The documentation of DateTimeFormatter.ISO_OFFSET_DATE_TIME
says that the format consists of:
- The
ISO_LOCAL_DATE_TIME
- The offset ID. … Parsing is case insensitive.
The last sentence allows upper case Z
and lower case z
for offset. The documentation of ISO_LOCAL_DATE_TIME
says about the T
:
- The letter 'T'. Parsing is case insensitive.
So this allows upper case T
and lower case t
.
We should not trust Java to tell us the truth about the standard. It seems that the ISO 8601 standard is a secret unless you pay for a copy (a funny way to persuade people to follow a standard IMHO). There’s a fine Wikipedia article on the standard. It gives the letters in upper case and does not mention whether they are allowed in lower case too.
Upvotes: 2
Reputation: 79085
Z
is not the same as z
.DateTimeFormatter
evaluates the former as zone-offset while the later as time-zone name.
Another example can be M
which it uses for month-of-year, and m
which it uses for minute-of-hour.
The symbol for the components of date, time, timezone etc. are case-sensitive. Check DateTimeFormatter
to learn more about these symbols.
A quick demo:
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
ZonedDateTime odt = ZonedDateTime.now(ZoneId.of("Asia/Calcutta"));
System.out.println(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssZ").format(odt));
System.out.println(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssz").format(odt));
}
}
Output:
2020-12-22T00:14:44+0530
2020-12-22T00:14:44IST
A zone offset is not the same as timezone. A timezone has an ID in the form, Continent/City
e.g. Asia/Calcutta
whereas a zone offset is represented in hours and minutes which tells how many hours and minutes the date & time of a place is offset from UTC
date & time. Thus, many timezone IDs can have the same zone offset. In other words, a zone offset can be derived from the timezone ID but the converse is not possible e.g. in the following demo, OffsetDateTime
will be able to determine the zone offset from the timezone ID of Asia/Calcutta
but trying to get the timezone name (as in the above example) using z
will fail.
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
OffsetDateTime odt = OffsetDateTime.now(ZoneId.of("Asia/Calcutta"));
System.out.println(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssZ").format(odt));
System.out.println(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssz").format(odt));
}
}
Output:
2020-12-22T00:30:40+0530
Exception in thread "main" java.time.DateTimeException: Unable to extract ZoneId from temporal 2020-12-22T00:30:40.865087+05:30
at java.base/java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:289)
at java.base/java.time.format.DateTimeFormatterBuilder$ZoneTextPrinterParser.format(DateTimeFormatterBuilder.java:4072)
at java.base/java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2341)
at java.base/java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1843)
at java.base/java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1817)
at Main.main(Main.java:9)
And I used "OffsetDateTime.parse()" (in java) to parse this format. I was able to parse date time by passing "t" (instead of "T") and "z" (instead of "Z") here.
I have already explained about Z
and z
. Let's focus on T
and t
. If you observe carefully, you will find that I've used single quotes around T
i.e. 'T'
which makes it a string literal to be used inside the date-time string. It means that it can be anything e.g. 't'
or 'Foo'
or 'Bar'
. As long as the literals in the DateTimeFormatter
matches in the same case with that in the date-time string, it works without any problem. I've shown it in the following demo:
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
String strDateTime = "2020-12-22T00:45:50+05:30";
// The given string is already in the format which is use by OffsetDateTime for
// parsing without a DateTimeFormatter
OffsetDateTime odt = OffsetDateTime.parse(strDateTime);
// Let's try to parse it using different types of DateTimeFormatter instances
System.out.println(OffsetDateTime.parse(strDateTime, DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXXX")));
//The following line will fail as the literal does not match case-wise
//System.out.println(OffsetDateTime.parse(strDateTime, DateTimeFormatter.ofPattern("uuuu-MM-dd't'HH:mm:ssXXX")));
strDateTime = "2020-12-22t00:45:50+05:30";// Now, DateTimeFormatter with 't' will work successfully
System.out.println(OffsetDateTime.parse(strDateTime, DateTimeFormatter.ofPattern("uuuu-MM-dd't'HH:mm:ssXXX")));
}
}
Output:
2020-12-22T00:45:50+05:30
2020-12-22T00:45:50+05:30
Learn more about the modern date-time API from Trail: Date Time.
Upvotes: 2
Reputation: 42302
So can anyone tell if it is allowed in ISO8601 or is it missed only in parsing logic?
I don't think it's valid to produce them though I guess it's fine (though not great) that the parser allows it.
The normative EBNF I have access to (8601-1 DIS Annex A) uses only uppercase latin letter for all designators, whether they be Z, T, W, R, P, Y, M, D, H, M, or S, and unlike (non-A) BNF, as far as I know EBNF terminals are case sensitive.
Upvotes: 4