Jasprit Singh Jasprit Singh - 1 year ago 69
Java Question

Java TimeZone and Linux TimeZone Daylight Savings doesnot match

I need to create POSIX format of TimeZone as defined by the following format.

std offset dst [offset],start[/time],end[/time]

For ex for "America/New_York" the POSIX format is

Now the value M3.2.0/2 is represented in the form Mm.w.d/t.

This specifies day d of week w of month m. The day d must be between 0 (Sunday) and 6. The week w must be between 1 and 5; week 1 is the first week in which day d occurs, and week 5 specifies the last d day in the month. The month m should be between 1 and 12. I borrowed the above explanation from the following link


So the above example states, the normal offset from UTC is 5 hours; since this is west of the prime meridian, the sign is positive. Summer time begins on March’s second Sunday at 2:00am and ends on November’s first Sunday at 2:00am.

When I check this in Linux timezone file /usr/share/zoneinfo/America/New_York, it matches the above value


However when I construct this in java for timezone "America/New_York" I get the following string


I constructed the above string by extracting the information from the output of the following code.

TimeZone timezone = TimeZone.getTimeZone("America/New_York");

The output is as below


Notice the values endMonth=10 which should be 11 as compared to Linux output.

Answer Source

Relying on the output of toString is not advisable, since there are no contractual guarantees about its format in either the TimeZone or SimpleTimeZone classes.

Obviously, your month numbers are off by one; the week of the month isn’t quite as simple, since you need to take into account the first full week of the month.

I would use Java’s documented public methods to get the information:

static String posixSpecFor(TimeZone tz) {
    Formatter posixSpec = new Formatter();

    float offset = (float) tz.getRawOffset() / (1000 * 60 * 60) * -1;
        tz.getDisplayName(false, TimeZone.SHORT),
        offset >= 0 ? "+" : "",
        new DecimalFormat("0.##").format(offset));

    if (tz.observesDaylightTime()) {
        posixSpec.format("%s", tz.getDisplayName(true, TimeZone.SHORT));

    ZoneId zone = tz.toZoneId();

    TemporalField weekOfMonth =
        WeekFields.of(DayOfWeek.SUNDAY, 7).weekOfMonth();
    int thisYear = Year.now(zone).getValue();

    List<ZoneOffsetTransitionRule> rules =
    if (rules.size() > 2) {
        rules = rules.subList(0, 2);

    for (ZoneOffsetTransitionRule rule : rules) {
            rule.getDayOfWeek().getValue() % 7,

    return posixSpec.toString();