简体   繁体   English

CST / CDT时区更改问题

[英]CST/CDT time zone change issue

We are storing time in like '22-NOV-17 05.33.51.937000000 PM' format with server default timezone CST. 我们使用服务器默认时区CST以“ 22-NOV-17 05.33.51.937000000 PM”格式存储时间。 We have half an our time comparison in many places. 在很多地方,我们的时间比较只有一半。 So CST to CDT and CDT to CST are facing issues because on retrieval time for database we can not identify the time zone. 因此,从CST到CDT以及从CDT到CST都面临着问题,因为在数据库的检索时间上,我们无法确定时区。 So it is breaking our time comparison on CST to CDT and CDT to CST time changes. 因此,这打破了我们在CST与CDT和CDT与CST的时间变化上的时间比较。

We can not change our storing logic like store with timezone and store in UTC timezone because it will breaking our existing logic in many places. 我们无法更改存储逻辑(如带时区存储和以UTC时区存储),因为它将在许多地方破坏我们现有的逻辑。

So is there any way to identity date timezone like CST or CDT, stored in database with '22-NOV-17 05.33.51.937000000 PM' format. 因此,有什么方法可以标识日期时区(例如CST或CDT),并以'22 -NOV-17 05.33.51.937000000 PM'格式存储在数据库中。

We are storing time in like '22-NOV-17 05.33.51.937000000 PM' format 我们以'22 -NOV-17 05.33.51.937000000 PM'格式存储时间

does not make sense with your comment 您的评论没有道理

We are storing as a timestamp in database 我们将时间戳记存储在数据库中

In Oracle databases, a TIMESTAMP does not have a format - it is stored in the database as 11 bytes representing year (2 bytes), month, day, hours, minutes, seconds (1 byte each) and fractional seconds (4 bytes). 在Oracle数据库中, TIMESTAMP没有格式-它以11个字节的形式存储在数据库中,代表年(2个字节),月,日,小时,分钟,秒(每个1字节)和小数秒(4个字节)。 It is only when whatever interface you are using (SQL/Plus, SQL Developer, Toad, Java, PHP, etc.) to talk to the database decides to show it to you, the user, that that interface will format it as a string (but the database will just keep it as bytes without any format). 只有当您使用的与数据库进行通信的任何接口(SQL / Plus,SQL Developer,Toad,Java,PHP等)决定向用户显示该接口时,该接口才会将其格式化为字符串(但是数据库只会将其保留为字节,没有任何格式)。

Assuming you are using SQL/Plus or SQL Developer then you can find the default format using: 假设您正在使用SQL / Plus或SQL Developer,则可以使用以下方法找到默认格式:

SELECT value FROM NLS_SESSION_PARAMETERS WHERE parameter = 'NLS_TIMESTAMP_FORMAT';

And change the default format using: 并使用以下命令更改默认格式:

ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SSXFF9';

Or for TIMESTAMP WITH TIME ZONE 或带TIMESTAMP WITH TIME ZONE

ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SSXFF9 TZR';

So is there any way to identity date timezone like CST or CDT, stored in database with '22-NOV-17 05.33.51.937000000 PM' format. 因此,有什么方法可以标识日期时区(例如CST或CDT),并以'22 -NOV-17 05.33.51.937000000 PM'格式存储在数据库中。

No, without any other meta-data that could identify the source of the timestamp and indicate which location it came from (ie is there another column that links to the user who entered the data that could be mapped to a physical location and so a time zone) then it is impossible to determine which time zone it is from. 不,没有任何其他元数据可以标识时间戳的来源并指示时间戳的来源(即是否存在另一列,该列链接到输入了可以映射到实际位置的数据的用户,因此还有一个时间)区域),则无法确定它来自哪个时区。

You will either need to: 您要么需要:

  • change your database column to TIMESTAMP WITH TIME ZONE and store the time zone; 将您的数据库列更改为TIMESTAMP WITH TIME ZONE并存储时区; or 要么
  • convert all the values to the same time zone when you are storing them. 存储它们时,请将所有值转换为相同的时区。

I am assuming by CST and CDT you mean North American Central Standard Time and Central Daylight Time such as observed in Rainy River, Chicago and Mexico (the city) among other places. 我假设CST和CDT表示的是北美中部标准时间和中部夏令时,例如在Rainy River,芝加哥和墨西哥(城市)中观察到的其他时间。 More on this ambiguity later. 稍后会更多地讨论这种歧义。

For 99.977 % of all times it is fairly easy to know whether they are standard time or daylight saving time. 对于所有时间的99.977%,很容易知道它们是标准时间还是夏令时。 Only times from the two hours around the transition from DST to standard time are ambiguous, and as said in the comments, there is no way to know from the time stamp which is the right way to resolve this ambiguity. 从夏令时过渡到标准时间只有两个小时的时间是模棱两可的,正如评论中所说,没有办法从时间戳中得知这是解决这种歧义的正确方法。

java.time java.time

This answer will take you as far into the future as possible without taking you away from Java 7. You can still use java.time , the modern Java date and time API also known as JSR-310. 这个答案将带您迈向更远的未来,而无需离开java.time 。您仍然可以使用java.time (现代Java日期和时间API,也称为JSR-310)。 It has been backported to Java 6 and 7 in the ThreeTen Backport , so it's a matter of getting this and adding it to your project (just until one day you upgrade to Java 8 or later). 它已在ThreeTen Backport中被反向移植到Java 6和Java 7,因此,只需将其添加到项目中即可(直到升级到Java 8或更高版本之前)。

I am taking your word for your date-time string format. 我想说一下您的日期时间字符串格式。 What we can do with it: 我们可以做什么:

    DateTimeFormatter storedFormatter = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .appendPattern("d-MMM-uu hh.mm.ss.SSSSSSSSS a")
            .toFormatter(Locale.US);
    ZoneId zone = ZoneId.of("America/Mexico_City");

    String storedTime = "22-NOV-17 05.33.51.937000000 PM";
    LocalDateTime dateTime = LocalDateTime.parse(storedTime, storedFormatter);
    // First shot -- will usually be correct
    ZonedDateTime firstShot = ZonedDateTime.of(dateTime, zone);
    System.out.println(firstShot);

This prints: 打印:

2017-11-22T17:33:51.937-06:00[America/Mexico_City]

You can see that it picked an offset of -06:00, which means that the time is in standard time (CDT is -05:00). 您会看到它选择了-06:00的偏移量,这意味着该时间处于标准时间(CDT为-05:00)。

Since your month abbreviation is in all uppercase, I needed to tell the formatter to parse case insensitively. 由于您的月份缩写全为大写,因此我需要告诉格式化程序不区分大小写地解析大小写。 If America/Mexico_City time zone is not appropriate for you, pick a better one, for example America/Rainy_River or America/Chicago. 如果America / Mexico_City时区不适合您,请选择一个更好的时区,例如America / Rainy_River或America / Chicago。

Ambiguous times in fall 秋天的times昧时代

I once had to parse a log file containing date-times without indication of standard time and summer time (DST). 我曾经不得不解析一个包含日期时间的日志文件,而没有指示标准时间和夏令时(DST)。 Since we assumed time would always move forward, we failed at the transition to standard time, and one hour of the log file was lost. 由于我们假设时间总是会向前发展,因此在过渡到标准时间时我们失败了,一小时的日志文件丢失了。 In this case we might have solved it using the information that times were in summer time until the leap backward by an hour, from there they were in standard time. 在这种情况下,我们可能使用夏时制直到从标准时间开始向后跳一个小时的信息解决了这一问题。 You may want to think about whether something similar will be possible for you. 您可能要考虑是否可能为您提供类似的服务。

Other options include just taking DST time every time — this is what the above code will do — or taking an average and living with the error thus introduced. 其他选择包括每次仅花费DST时间-这就是上面的代码所要做的-或取平均值并忍受由此带来的错误。

We can at least detect the ambiguous times: 我们至少可以检测到模棱两可的时间:

    ZoneOffset standardOffset = ZoneOffset.ofHours(-6);
    ZoneOffset dstOffset = ZoneOffset.ofHours(-5);
    // check if in fall overlap
    ZonedDateTime standardDateTime 
            = ZonedDateTime.ofLocal(dateTime, zone, standardOffset);
    ZonedDateTime dstDateTime 
            = ZonedDateTime.ofLocal(dateTime, zone, dstOffset);
    if (! standardDateTime.equals(dstDateTime)) {
        System.out.println("Ambiguous, this could be in CST or CDT: " + dateTime);
    }

Now if the string was 29-OCT-17 01.30.00.000000000 AM , I get the message 现在,如果字符串是29-OCT-17 01.30.00.000000000 AM ,我会收到消息

Ambiguous, this could be in CST or CDT: 2017-10-29T01:30

ZonedDateTime.ofLocal() will use the provided offset for resolving the ambiguity if it is a valid offset for the date-time and zone. ZonedDateTime.ofLocal()将使用提供的偏移量来解决歧义,如果它是日期时间和区域的有效偏移量。

Non-existing times in the spring 春天不存在的时候

Similarly we can detect if your date-time falls in the gap where the clock is moved forward in the transition to DST: 同样,我们可以检测到您的日期时间是否落在转换为DST的时钟向前移动的间隙中:

    // Check if in spring gap
    if (! firstShot.toLocalDateTime().equals(dateTime)) {
        System.out.println("Not a valid date-time, in spring gap: " + dateTime);
    }

This can give a message like 这可以给出类似的信息

Not a valid date-time, in spring gap: 2018-04-01T02:01

I suggest you can safely reject such values. 我建议您可以放心拒绝这些值。 They cannot be correct. 他们是不正确的。

Avoid the three letter time zone abbreviations 避免三个字母的时区缩写

CST may refer to Central Standard Time (in North and Central America), Australian Central Standard Time, Cuba Standard Time and China Standard Time. CST可以参考中部标准时间(在北美和中美洲),澳大利亚中部标准时间,古巴标准时间和中国标准时间。 CDT may mean Central Daylight Time or Cuba Daylight Time. CDT可能表示中部夏令时或古巴夏令时。 The three and four letter abbreviations are not standardized and are very often ambiguous. 三个和四个字母的缩写不标准化,并且常常是模棱两可的。 Prefer time zone IDs in the region/city format, for example America/Winnipeg. 最好使用地区/城市格式的时区ID,例如America / Winnipeg。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM