为日历对象禁用 DST

Posted

技术标签:

【中文标题】为日历对象禁用 DST【英文标题】:Disable DST for Calendar object 【发布时间】:2021-01-24 15:36:27 【问题描述】:

我正在解析一个逗号分隔的文件,该文件有两个需要转换为时间戳的字段。我得到了一个日期,一个单独的字段给了我午夜过去的分钟数......例如:

2020 年 10 月 15 日,360 度

现在 360,在大多数日子里,是早上 6 点(360/60 = 6),但在 DST 上说它可能是 5 点或 7 点。问题是我总是希望输出早上 6 点,即使它是 DST 日。

Calendar cal = Calendar.getInstance();
cal.setTime(schedDate);

cal.add(Calendar.MINUTE, Integer.parseInt(minutes));

return new Timestamp(cal.getTimeInMillis());

我尝试添加以下内容:

cal.set(cal.DST_OFFSET, 0);

但这似乎并不能解决问题。我不确定日历是否有任何内置功能来禁用 DST 偏移,但任何建议都将不胜感激

【问题讨论】:

这取决于哪个时区或偏移量?系统之一还是一些固定的? 我猜有没有?我采用系统默认设置,但无论它在哪个时区运行,我都希望 360 等于一年中的每一天早上 6 点。 然后使用@ArvindKumarAvinash 或我的答案给出的答案...两者都将分钟添加到解析的日期,以获得所需的一天中的时间。 我建议您既不要使用Calendar,也不要使用java.sql.Timestamp。这些类设计不佳且早已过时,尤其是前者,尤其是出了名的麻烦。而是使用来自java.time, the modern Java date and time API 的类。 【参考方案1】:

使用LocalDateTime,它不需要处理时区(因此也需要处理 DST)。请注意,LocalDateTime 是 the modern date-time API 的一部分。

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Main 
    public static void main(String[] args) 
        LocalDateTime ldt = LocalDate.parse("10/15/2020", DateTimeFormatter.ofPattern("M/d/u")).atStartOfDay()
                .plusHours(6);
        System.out.println(ldt);
    

输出:

2020-10-15T06:00

我还建议您停止使用容易出错且已过时的java.util date-time API。

如果您正在为您的 android 项目执行此操作,并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaring 和 How to use ThreeTenABP in Android Project。

通过 Trail: Date Time 了解有关现代日期时间 API 的更多信息。

【讨论】:

【参考方案2】:

使用java.time,可以涉及系统的时区,也可以给它一个固定的时区。

下面的代码展示了如何做到这一点:

public static void main(String[] args) 
    // example input
    String date = "10/15/2020";
    long minutes = 360;
    // create a LocalDate from the String considering its format
    LocalDate localDate = LocalDate.parse(date, DateTimeFormatter.ofPattern("MM/dd/uuuu"));
    // create a minimum LocalTime (the beginning of a day) and add the minutes you got
    LocalTime timeOfDay = LocalTime.MIN.plusMinutes(minutes);
    // create a zone-aware object by using the date, the time of day and the system's zone
    ZonedDateTime zonedDateTime = ZonedDateTime.of(localDate,
                                                    timeOfDay, 
                                                    ZoneId.systemDefault());
    // print the toString() method (implicitly)
    System.out.println(zonedDateTime);
    // or use a custom format
    System.out.println(zonedDateTime.format(DateTimeFormatter
                                            .ofPattern("MM/dd/uuuu HH:mm:ss")));

它输出以下内容(在 UTC+2 的系统上运行):

2020-10-15T06:00+02:00[Europe/Berlin]
10/15/2020 06:00:00

【讨论】:

【参考方案3】:

现在,我们可以让 java.time 解析 CSV 文件(逗号分隔值文件)中的两个字段并将它们组合起来:

        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("M/d/u");
        DateTimeFormatter minuteOfDayFormatter = new DateTimeFormatterBuilder()
                .appendValue(ChronoField.MINUTE_OF_DAY)
                .toFormatter();
        
        String dateString = "10/15/2020";
        String timeString = "360";
        
        LocalDate date = LocalDate.parse(dateString, dateFormatter);
        LocalTime time = LocalTime.parse(timeString, minuteOfDayFormatter);
        LocalDateTime dateTime = date.atTime(time);
        
        System.out.println(dateTime);

输出是:

2020-10-15T06:00

如果您认为您的 SQL 数据库需要 java.sql.Timestamp,那么您很可能不需要。您可以使用例如PreparedStatement.setObject()LocalDateTime 对象传递到您的数据库。如果您需要控制时区(通常是个好主意),请先将其转换为OffsetDateTimeInstant。搜索方法。

【讨论】:

这正是我在阅读了 Arvind 和 deHaar 的回复后所做的!谢谢你让我觉得我在正确的道路上哈哈。

以上是关于为日历对象禁用 DST的主要内容,如果未能解决你的问题,请参考以下文章

将日期对象转换为日历对象 [重复]

Java 日历:凌晨 1 点切换到标准时间(从 DST 开始)

Java 为啥 Calendar.get(Calendar.DST_OFFSET) 在夏令时给出 0?

日期对象到日历对象的转换

在 Java 中将字符串转换为日历对象

如何将日期字符串转换为日期或日历对象?