在我的应用程序中,用户可以创建重复事件,例如“每个星期六中午12点午餐”。
现在我遇到了一个问题,我不知道如何正确处理。如果事件链很大,并且具有不同的时区(冬季和夏季时间),则列出所有这些事件显示不同的时间。
例如,存储服务器端的日期如下:
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)在第二次和第三次之间,客户更改为冬季时间和+01:00。时间会相应地调整,用户可能会认为事件会突然开始,而且会提前一小时,即使它是在同一时间开始的。
我希望它在客户端解析时总是显示事件时间(12:00),而不管时区如何。另一种解决方案是,如果该信息可以用Joda时间提取,则说明在夏季/冬季时间显示的信息。
发布于 2017-10-27 11:03:48
如果您想要的话,我会使用java8 LocalDateTime类服务器端,忽略时区。
LocalDateTime完全是为了处理不需要时区信息而声明日期(和时间)的情况。
如果数据库不支持存储时区少的日期时间,则每次都可以使用相同的时区(例如UTC)将其转换为服务器上的时间戳。只需确保将其发送到客户端,并将其作为LocalDateTime从客户端接收。
编辑:为了响应下面的注释,如果要根据用户的本地时区向用户显示日期,最好将ZonedDateTime存储在标准时区(例如,UTC),并存储用户的现场。然后,您可以使用区域设置将日期转换为特定于用户的日期格式,这将使DST和其他时区更改牢记在心。
EDIT2:对于转换日期时间,您可以使用区域ZoneId。区域设置对于格式化仍然很有用。
发布于 2018-05-23 02:55:01
java.time
Buurman的答复几乎是正确的,但并不完全正确。
Joda-Time项目确实处于维护模式,其创建者建议迁移到Java8及更高版本中的java.time类。Joda-Time和java.time JSR 310都是由同一个人,Stephen领导的.因此,迁移是相当容易的,因为许多核心思想是相同的。
如果你试图代表“每周六中午的午餐”,你就无法可靠地存储未来的确切时刻。世界各地的政治家都表现出重新定义时区的倾向。他们这样做的次数令人惊讶,而且通常是在很少有警告的情况下这样做的。所以,你不可能知道“中午”是什么时候,从一天中的时间来看。时钟定义的变化意味着你在追逐一个移动的目标。
因此,“每周六中午的午餐”需要跟踪一周的一天和一天的时间。Java有两个类。
DayOfWeek dayOfWeek = DayOfWeek.SATURDAY ; // Enum with seven predefined objects, Monday-Saturday.
LocalTime localTime = LocalTime.of( 12 , 0 ) ; // Noon.当您说“中午”时,您还需要存储预定的时区。每一天,印度的中午时间都比法国早得多,魁北克的午休时间甚至更晚。因此,一天中的时间只有在特定时区的上下文中才有意义。
以continent/region格式指定continent/region,如America/Montreal、Africa/Casablanca或Pacific/Auckland。不要使用3-4字母的缩写,如EST或IST,因为它们不是真正的时区,不标准化,甚至不是唯一的(!)。
ZoneId zoneId = ZoneId.of( "America/Montreal" ) ;您可以投影出一系列这些午餐,确定每个午餐的确切时刻(时间线上的点)。但你只能暂时这么做。鉴于各国政府已经证明,它们愿意重新定义时区的抵消值,只需几个月、几周、天数甚至小时数的预警,你就无法储存这些预测。在运行时动态地计算它们。
今天就决定。这当然需要一个时区。在任何特定时刻,全球各地的日期因地区而异。
LocalDate today = LocalDate.now( zoneId ) ;下个星期六去,如果已经是星期六,就呆在今天。
LocalDate firstSaturday = today.with( TemporalAdjusters.nextOrSame( dayOfWeek ) ) ;确定该日期该区域正午时间线上的点。
ZonedDateTime firstLunch = ZonedDateTime.of( firstSaturday , localTime , zoneId ) ;您可以通过提取Instant来查看与UTC相同的时刻。
Instant firstLunchInstant = firstLunch.toInstant() ;您可以通过在LocalDate中添加一个星期,并重复上面的步骤,在下一个日期要求中午,来继续这个预测。如果这一天的时间恰好在该区域的该日期无效(例如夏时制时间“Spring- adjusts”切入),则ZonedDateTime类将相应地进行调整。请务必阅读文档以了解其调整算法。
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 ) ;
}数据库
至于将“每周六中午午餐”存储在数据库中:
TIME WITHOUT TIME ZONE类型中.
myPreparedStatement.setObject( … , localTime ) ;
LocalTime localTime = myResultSet.getObject( … , LocalTime.class ) ;DayOfWeek枚举值名称(如MONDAY )存储在VARCHAR中。或者,您可以将每周的天数存储为整数。对于一个数字,我强烈建议周一至周日使用ISO 8601标准1-7。一定要清楚地记录你的号码对后代的意义。ZonedDateTime对象应该是暂时的,根据需要动态创建。所以你不会把它们储存起来。
关于java.time
http://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html框架内置到Java8和更高版本中。这些类取代了麻烦的旧遗赠日期时间类,如java.util.Date、Calendar和SimpleDateFormat。
http://www.joda.org/joda-time/项目现在在维护模式中,建议迁移到java.time类。
要了解更多信息,请参见http://docs.oracle.com/javase/tutorial/datetime/TOC.html。并搜索堆栈溢出以获得许多示例和解释。规范是JSR 310。
您可以直接与数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC 4.2。不需要字符串,也不需要java.sql.*类。
在哪里获得java.time类?
三次-额外项目使用其他类扩展java.time。这个项目是将来可能加入java.time的试验场。您可以在这里找到一些有用的类,如Interval、YearWeek、YearQuarter和更多。
https://stackoverflow.com/questions/46973401
复制相似问题