Java 如何解析Datetime并将其与相应的时区关联

Java 如何解析Datetime并将其与相应的时区关联,java,scala,date,datetime,timezone,Java,Scala,Date,Datetime,Timezone,我正在尝试读取格式为2019-12-23 13:35:00的字符串,以创建DateTime对象并将其与我知道它对应的特定时区关联(GMT-5) 我正试图这样做: val string1 = "2019-12-23 13:35:00" val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") sdf.setTimeZone(StaticDateTimeZone.forID("Etc/GMT-5").toTimeZone)

我正在尝试读取格式为
2019-12-23 13:35:00
的字符串,以创建DateTime对象并将其与我知道它对应的特定时区关联(GMT-5)

我正试图这样做:

 val string1 = "2019-12-23 13:35:00"
    val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    sdf.setTimeZone(StaticDateTimeZone.forID("Etc/GMT-5").toTimeZone)
    val date = sdf.parse(string1)
输出不是我想要的,因为它不是假设datetime不在GMT-5时区,而是在我的系统时区(GMT+0)中,将datetime调整为GMT-5如下:
Mon Dec 23 08:35:00 GMT 2019

我如何创建一个不改变输入的datetime对象,而只是将一个时区与之关联?

您似乎正在使用它,然后将其转换为
java.util.Date
。您可以直接使用java 8中的
java.time
包:

val string1 = "2019-12-23 13:35:00"
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
val date = LocalDateTime.parse(string1, formatter)
date.atZone(ZoneId.of("Etc/GMT-5"))
其中:

date: java.time.LocalDateTime = 2019-12-23T13:35
res0: java.time.ZonedDateTime = 2019-12-23T13:35+05:00[Etc/GMT-5]
LocalDateTime
生成一个没有附加任何时区的日期。最后一行有效地从上一个日期创建了一个新的
ZonedDateTime
,并将给定的时区添加到其上。如果需要返回到
java.util.Date
,请参阅。

  • 我建议使用JodaTime
  • JodaTime最适合使用时区
例如,我编写了一个方法:

公共静态日期getDateWithTimeZone(字符串日期字符串、字符串格式、字符串时区){
DateFormat df=新的SimpleDataFormat(格式);
Date dateObj=null;
试一试{
dateObj=df.parse(dateString);
DateTime DateTime=新的DateTime(dateObj);
时区=时区。getTimeZone(时区);
返回dateTime.withZoneRetainFields(DateTimeZone.forTimeZone(zone))
.toDate();
}捕获(解析异常){
logger.error(“将字符串转换为日期时出错”,e);
}
返回null;
}
  • 您可以根据需要更改方法/异常处理。 希望这有帮助

您可以按如下方式执行:

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

public class Main {
    public static void main(String[] args) {
        String strDateTime = "2019-12-23 13:35:00";
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime ldt = LocalDateTime.parse(strDateTime, format);
        ZoneId gmtZoneId = ZoneId.of("UTC+00:00");
        ZoneId myZoneId = ZoneId.of("UTC-05:00");
        System.out.println(format.format(ldt.atZone(gmtZoneId).withZoneSameInstant(myZoneId)));
    }
}
输出:

2019-12-23 08:35:00
2019-12-23 08:35:00
帮助文档:

2019-12-23 08:35:00
2019-12-23 08:35:00
  • [更新]

    根据Basil Bourque的评论发布以下代码:

    import java.time.LocalDateTime;
    import java.time.ZoneOffset;
    import java.time.format.DateTimeFormatter;
    
    public class Main {
        public static void main(String[] args) {
            String strDateTime = "2019-12-23 13:35:00";
            DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            LocalDateTime ldt = LocalDateTime.parse(strDateTime, format);
            System.out.println(format.format(ldt.atZone(ZoneOffset.of("+00:00")).withZoneSameInstant(ZoneOffset.of("-05:00"))));
        }
    }
    
    输出:

    2019-12-23 08:35:00
    
    2019-12-23 08:35:00
    
    (使用Java语法而不是Scala)

    tl;博士 我知道它所对应的特定时区(GMT-5)

    GMT-5
    不是时区,它只是一个偏移量。时区的名称为
    大陆/地区
    格式,例如
    非洲/突尼斯
    。时区是区域使用的偏移量变化的历史记录

    您无法根据偏移量可靠地确定时区。许多时区在特定时刻可能共享相同的偏移量,但在其他时刻可能不同。所以你只是在胡乱猜测。仅当您确定知道特定区域时,才应用时区

    相反,使用偏移量本身来确定力矩,不带区域。这里是一个单线解决方案

    LocalDateTime                                     // Represent a date with time-of-day but lacking the context of an offset-from-UTC or a time zone.
    .parse(                                           // When parsing, no need to specify a formatting pattern when the input complies with the ISO 8601 standard.        
        "2019-12-23 13:35:00".replace( " " , "T" )    // Comply with ISO 8601 standard formatting, replacing SPACE in the middle with an uppercase `T`. 
    )                                                 // Returns a `LocalDateTime` object.
    .atOffset(                                        // Determine a moment by placing the date and time-of-day of a `LocalDateTime` into the context of an offset-from-UTC.
        ZoneOffset.ofHours( -5 )                      // Represent an offset-from-UTC with `ZoneOffset`, merely a number of hours-minutes-seconds ahead or behind the prime meridian. 
    )                                                 // Returns a `OffsetDateTime` object.
    .toString()                                       // Generate text in standard ISO 8601 format.
    

    2019-12-23T13:35-05:00

    java.time ISO 8601 您的输入字符串几乎是ISO8601标准格式。要遵守,用“<代码> t>代码>替换中间的空间。
    String input = "2019-12-23 13:35:00".replace( " " , "T" ) ;
    
    LocalDateTime
    考虑到您的输入缺少时区或UTC偏移量,将其解析为
    LocalDateTime

    LocalDateTime ldt = LocalDateTime.parse( input ) ;
    
    请注意,
    LocalDateTime
    不是一个时刻,也不是时间线上的一个点。在您的示例中,大约下午1:30,我们不知道这是指日本东京的下午1:30,还是美国俄亥俄州托莱多的下午1:30,这两个时刻相差很多小时

    OffsetDateTime
    您声称明确知道该日期和时间是通过UTC后五小时(通常在本初子午线以西)的偏移镜头看到的

    因此,让我们应用
    ZoneOffset
    来获得
    OffsetDateTime

    OffsetDateTime odt = ldt.atOffset( offset ) ;
    
    看这个

    odt.toString():2019-12-23T13:35-05:00

    ZoneDateTime
    时区总是比仅从UTC偏移更可取。偏移量是小时数——分秒,仅此而已。时区更重要。时区是特定地区人民使用的偏移量的过去、现在和未来变化的历史

    但不要猜测时区。仅当您知道
    LocalDateTime
    对象最初用于该区域时,才应用区域

    大陆/地区
    的格式指定,例如
    美国/蒙特利尔
    非洲/卡萨布兰卡
    ,或
    太平洋/奥克兰
    。切勿使用2-4个字母的缩写,如
    EST
    IST
    ,因为它们不是真正的时区,也不是标准化的,甚至不是唯一的(!)



    关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&

    要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是

    该项目现已启动,建议迁移到类

    您可以直接与数据库交换java.time对象。使用兼容的或更高版本。不需要字符串,也不需要
    java.sql.*

    从哪里获得java.time类

    • 、和更高版本-标准Java API的一部分,带有捆绑实现。
      • Java9添加了一些次要功能和修复
      • 大多数java.time功能都在中向后移植到Java6和Java7
      • 更高版本的Android捆绑包实现了java.time类

      • 对于早期的Android(仅供参考:该项目现在正在进行中。它的创建者继续领导定义内置于Java 8+中的类。请参阅。基本上是正确的,但您应该使用
        ZoneOffset
        进行偏移,而不是
        ZoneId
        ,后者用于时区。谢谢,这是最完整的