Java 重复事件日期处理冬季时间/夏季时间

Java 重复事件日期处理冬季时间/夏季时间,java,jodatime,Java,Jodatime,在我的应用程序中,用户可以创建重复事件,例如“每周六12:00午餐” 现在我遇到了一个问题,我不知道如何正确处理。如果事件链很大且时区不同(冬季和夏季),则列出所有这些事件会显示不同的时间 例如,日期存储在服务器端为: 2017-10-28T12:00:00.000+02:00 因此,在列出客户端事件时,它可以如下所示: 2017-10-21 12:00:00.000 (parsed from: 2017-10-21T12:00:00.000+02:00) 2017-10-28 12:00:0

在我的应用程序中,用户可以创建重复事件,例如“每周六12:00午餐”

现在我遇到了一个问题,我不知道如何正确处理。如果事件链很大且时区不同(冬季和夏季),则列出所有这些事件会显示不同的时间

例如,日期存储在服务器端为:

2017-10-28T12:00:00.000+02:00
因此,在列出客户端事件时,它可以如下所示:

2017-10-21 12:00:00.000 (parsed from: 2017-10-21T12:00:00.000+02:00)
2017-10-28 12:00:00.000 (parsed from: 2017-10-28T12:00:00.000+02:00)
2017-11-04 11:00:00.000 (parsed from: 2017-11-04T12:00:00.000+02:00)
2017-11-11 11:00:00.000 (parsed from: 2017-11-11T12:00:00.000+02:00)
在第2次和第3次之间,客户更改为冬季时间和+01:00。时间会相应地进行调整,用户可能会认为活动时间突然开始,并且提前了一个小时,即使它在同一时间开始

我希望它在客户端解析时总是显示事件时间(12:00),而不考虑时区。另一种解决方案是,如果可以使用Joda time提取信息,则说明夏季时间/冬季时间显示的时间。

如果您需要,我将使用java8类服务器端并忽略时区

LocalDateTime正是为了处理您希望在没有时区信息的情况下声明日期(和时间)的情况

如果您的数据库不支持存储时区较少的日期时间,则每次都可以在服务器上使用相同的时区(例如UTC)将其与时间戳进行转换。只需确保将其作为LocalDateTime发送到客户端,并从客户端接收即可

编辑:对于下面的评论,如果您想根据用户的本地时区向用户显示日期,最好将ZonedDateTime存储在标准时区(例如UTC)中,并存储用户的日期。然后,您可以使用区域设置将日期转换为用户特定的日期格式,这将记住DST和其他时区更改

EDIT2:要转换日期时间,可以使用区域。区域设置对于格式化仍然很有用。

如果您需要的话,我会使用java8类服务器端并忽略时区

LocalDateTime正是为了处理您希望在没有时区信息的情况下声明日期(和时间)的情况

如果您的数据库不支持存储时区较少的日期时间,则每次都可以在服务器上使用相同的时区(例如UTC)将其与时间戳进行转换。只需确保将其作为LocalDateTime发送到客户端,并从客户端接收即可

编辑:对于下面的评论,如果您想根据用户的本地时区向用户显示日期,最好将ZonedDateTime存储在标准时区(例如UTC)中,并存储用户的日期。然后,您可以使用区域设置将日期转换为用户特定的日期格式,这将记住DST和其他时区更改

EDIT2:要转换日期时间,可以使用区域。区域设置对于格式化仍然很有用。

java.time 答案几乎正确,但不完全正确

Joda Time项目确实处于维护模式,其创建者建议迁移到java 8及更高版本中内置的java.Time类。Joda Time和java.Time JSR 310都由同一个人Stephen Colebourne领导。因此,迁移相当容易,因为许多核心思想都是相同的

如果你试图表示“每个周六中午吃午饭”,你就无法可靠地存储未来的确切时刻。世界各地的政治家都表现出对重新定义时区的偏好。他们经常出人意料地这样做,而且往往很少发出警告。所以你无法知道“中午”是什么时候,就时钟上的某个时间而言。时钟定义的改变意味着你在追逐一个移动的目标

所以,“每周六中午午餐”需要跟踪一周中的一天和一天中的一个时间。Java为这两者都提供了类

DayOfWeek dayOfWeek = DayOfWeek.SATURDAY ;  // Enum with seven predefined objects, Monday-Saturday.

LocalTime localTime = LocalTime.of( 12 , 0 ) ;  // Noon.
你还需要存储你说“中午”时的时区。印度每天中午的时间比法国早得多,魁北克更晚。因此,一天中的某个时间只有在特定时区的背景下才有意义

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

你可以计划一系列的午餐,确定每个午餐的确切时间(时间轴上的点)。但你只能暂时这么做。鉴于各国政府已证明他们愿意通过仅几个月、几个星期甚至几个月的预警来重新定义时区与UTC的偏移量,因此您无法存储这些预测。在运行时动态计算它们

今天决定。这当然需要一个时区。在任何一个特定的时刻,世界各地的日期都因地区而异

LocalDate today = LocalDate.now( zoneId ) ;
获得下一个星期六,或者如果已经是星期六,就留在今天

LocalDate firstSaturday = today.with( TemporalAdjusters.nextOrSame( dayOfWeek ) ) ;
确定该日期该区域中午时间线上的点

ZonedDateTime firstLunch = ZonedDateTime.of( firstSaturday , localTime , zoneId ) ;
通过提取一个
瞬间
,您可以查看与UTC相同的时刻

Instant firstLunchInstant = firstLunch.toInstant() ;
您可以通过在
LocalDate
中添加一周,并重复上述步骤来请求下一个日期的中午,从而继续此预测。如果该时间恰好在该区域的该日期无效(例如夏时制“提前春天”切换),则
zoneDateTime
类将相应调整。务必阅读单据,了解其调整算法

int weeksToProject = 10 ;  // Run out 10 weeks.
List< ZonedDateTime > lunches = new ArrayList<>( weeksToProject ) ;
LocalDate localDate = firstSaturday ;
for( int i = 0 ; i < 10 ; i ++ ) {
    localDate = localDate.plusWeeks( i ) ;
    ZonedDateTime zdt = ZonedDateTime.of( localDate , localTime , zoneId ) ;  
    lunches.add( zdt ) ;
}
int weeksToProject=10;//跑完10周。
列表午餐=新阵列列表(WeekstopProject);
LocalDate LocalDate=第一个星期六;
对于(int i=0;i<10;i++){
localDate=localDate.plusWeeks(i);
ZonedDateTime zdt=ZonedDateTime.of(localDate、localTime、zoneId);
午餐。添加(zdt);
}
数据库 至于储存“每周六午餐”
int weeksToProject = 10 ;  // Run out 10 weeks.
List< ZonedDateTime > lunches = new ArrayList<>( weeksToProject ) ;
LocalDate localDate = firstSaturday ;
for( int i = 0 ; i < 10 ; i ++ ) {
    localDate = localDate.plusWeeks( i ) ;
    ZonedDateTime zdt = ZonedDateTime.of( localDate , localTime , zoneId ) ;  
    lunches.add( zdt ) ;
}