Sentinel icon indicating copy to clipboard operation
Sentinel copied to clipboard

Fixed time format assertion failing due to daylight saving time

Open hermya opened this issue 1 year ago • 3 comments

Describe what this PR does / why we need it

PR intends to fix the test EagleEyeCoreUtilsTest.testFormatTime.

Does this pull request fix one issue?

Fixes https://github.com/alibaba/Sentinel/issues/3458

Describe how you did it

Used TimeZone.getDefault().getDSTSavings()

Describe how to verify it

Reran the test-case, now passing successfully

Special notes for reviews

hermya avatar Oct 19 '24 23:10 hermya

CLA assistant check
All committers have signed the CLA.

CLAassistant avatar Oct 19 '24 23:10 CLAassistant

With DSTSavings in mind, I think there should be three test cases:

  1. In a time zone that does not observe the DST, the local standard time is returned
  2. If the current time is not in the DST time zone, the returned value must be the same as the local standard time
  3. If the current time is within the DST range, the local wall time, which is inconsistent with the local standard time, is returned

robberphex avatar Oct 20 '24 03:10 robberphex

The latest commit contains TimeZone.getOffset() method. According to this, getOffset() should cater to DST, based on the zone and date.

I tried it with sample code for different zones and times as follows:

import java.sql.Date;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.TimeZone;
import java.util.stream.Collectors;

public class Main {

    public static DateTimeFormatter getFormatterByZone(String zoneId) {
        return DateTimeFormatter
            .ofPattern("yyyy-MM-dd HH:mm:ss.SSS")
            .withZone(ZoneId.of(zoneId));
    }

    public static void printZoneInformation(String zoneId) {
        var tz = TimeZone.getTimeZone(zoneId);
        System.out.println("Time zone: " + tz.getDisplayName() + ", RawOffset: " + tz.getRawOffset() + ", DST: " + tz.observesDaylightTime() + ", DSTSavings: " + tz.getDSTSavings());
    }

    public static long getOffsetForZone(String zoneId, long epoch) {
        return TimeZone.getTimeZone(zoneId).getOffset(epoch);
    }


    public static void main(String[] args) {
        // SAPST -> (UTC-05:00) Bogota, Lima, Quito No DST
        // IST -> (UTC+05:30) India Standard Time No DST
        // CDT -> (UTC-05:00) Central Daylight Time DST
        long epochNotInDST = 1729382400000l;
        long epochInDST = 1732060800000l;
        // 1729382400000l -> 10/20/2024 00:00:00.000 Date not in DST
        // 1732060800000l -> 11/20/2024 00:00:00.000 Date in DST

        System.out.println("\nDate in DST:    ");
        printZoneInformation("Etc/GMT+0");
        System.out.println(getFormatterByZone("Etc/GMT+0").format(Instant.ofEpochMilli(epochInDST - getOffsetForZone("Etc/GMT+0", epochInDST))));  
        printZoneInformation("America/Bogota");
        System.out.println(getFormatterByZone("America/Bogota").format(Instant.ofEpochMilli(epochInDST - getOffsetForZone("America/Bogota", epochInDST))));    
        printZoneInformation("Asia/Kolkata");
        System.out.println(getFormatterByZone("Asia/Kolkata").format(Instant.ofEpochMilli(epochInDST - getOffsetForZone("Asia/Kolkata", epochInDST))));    
        printZoneInformation("America/Chicago");
        System.out.println(getFormatterByZone("America/Chicago").format(Instant.ofEpochMilli(epochInDST - getOffsetForZone("America/Chicago", epochInDST))));    

        System.out.println("\nDate not in DST:    ");
        printZoneInformation("Etc/GMT+0");
        System.out.println(getFormatterByZone("Etc/GMT+0").format(Instant.ofEpochMilli(epochNotInDST - getOffsetForZone("Etc/GMT+0", epochNotInDST))));  
        printZoneInformation("America/Bogota");
        System.out.println(getFormatterByZone("America/Bogota").format(Instant.ofEpochMilli(epochNotInDST - getOffsetForZone("America/Bogota", epochNotInDST))));    
        printZoneInformation("Asia/Kolkata");
        System.out.println(getFormatterByZone("Asia/Kolkata").format(Instant.ofEpochMilli(epochNotInDST - getOffsetForZone("Asia/Kolkata", epochNotInDST))));    
        printZoneInformation("America/Chicago");
        System.out.println(getFormatterByZone("America/Chicago").format(Instant.ofEpochMilli(epochNotInDST - getOffsetForZone("America/Chicago", epochNotInDST)))); 
    }
}

And got the output:

Date in DST:
Time zone: Greenwich Mean Time, RawOffset: 0, DST: false, DSTSavings: 0
2024-11-20 00:00:00.000
Time zone: Colombia Standard Time, RawOffset: -18000000, DST: false, DSTSavings: 0
2024-11-20 00:00:00.000
Time zone: India Standard Time, RawOffset: 19800000, DST: false, DSTSavings: 0
2024-11-20 00:00:00.000
Time zone: Central Standard Time, RawOffset: -21600000, DST: true, DSTSavings: 3600000
2024-11-20 00:00:00.000

Date not in DST:
Time zone: Greenwich Mean Time, RawOffset: 0, DST: false, DSTSavings: 0
2024-10-20 00:00:00.000
Time zone: Colombia Standard Time, RawOffset: -18000000, DST: false, DSTSavings: 0
2024-10-20 00:00:00.000
Time zone: India Standard Time, RawOffset: 19800000, DST: false, DSTSavings: 0
2024-10-20 00:00:00.000
Time zone: Central Standard Time, RawOffset: -21600000, DST: true, DSTSavings: 3600000
2024-10-20 00:00:00.000

hermya avatar Oct 20 '24 21:10 hermya