Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are time zone designators- "T" and "Z" case sensitive in ISO8601 format?

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?

like image 474
Aishwer Sharma Avatar asked Dec 01 '20 08:12

Aishwer Sharma


2 Answers

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.

like image 187
Masklinn Avatar answered Sep 28 '22 03:09

Masklinn


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.

like image 37
Arvind Kumar Avinash Avatar answered Sep 28 '22 03:09

Arvind Kumar Avinash