tl;博士
您必须了解“正常”calendar year 和 standard week-based year 之间的区别。日历年的第一天/最后几天可能出现在基于上一周/下一周的年份中。
当然,2014 日历年于 2014 年 12 月 31 日结束。但 2014 年的最后一天落在了 2015 年下周。
2014 年的最后一天于 2014 年 12 月 28 日(日历年)结束。基于周的 2015 年的第一天是 2014 年 12 月 29 日(日历年)。上面的日历图应该清楚地说明这些事实。
2014-12-28 = 2014-W52-7
2014-12-29 = 2015-W01-1
2015-01-01 = 2015-W01-4
询问基于周和年的数字:
myZonedDateTime.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR )
……和……
myZonedDateTime.get( IsoFields.WEEK_BASED_YEAR )
简而言之:在一年的最后/最初几天,调用myZonedDateTime.getYear() 和myZonedDateTime.get( IsoFields.WEEK_BASED_YEAR ) 的结果可能不同。
java.time
现代方法使用 java.time 类取代了麻烦的旧旧日期时间类。
为了管理日期,我使用了日历课程。我在数据库中保存时间戳,使用Calendar timestamp = Calendar.getInstance();
相反,请使用ZoneDateTime 以特定地区(时区)的人们使用的挂钟时间来捕捉当前时刻。
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
我可以使用长值来保存和检索数据库中的日期来存储日期。
不,在定义数据库列和 Java 代码时使用适当的数据类型。
要在符合 SQL 标准的数据库中存储时间线上的特定时刻,请将列定义为 TIMESTAMP WITH TIME ZONE。
使用 JDBC 4.2 及更高版本,您可以直接与数据库交换 java.time 对象。
myPreparedStatement.setObject( … , zdt ) ;
以Instant 的形式检索,UTC 时刻,可能是另一个方向的最佳路线。然后调整到您想要的时区。
Instant instant = myResultSet.getObject( … , Instant.class ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
这是我的问题:当我要存储时间戳时,我需要知道数据库中是否已经存在属于同一周的时间戳。为此,我想我可以使用以下两种方法:timestamp.get(Calendar.YEAR) 和 timestamp.get(Calendar.WEEK_OF_YEAR)
不幸的是,令人困惑的Calendar 类中一周的含义因地区而异。
也许你自己的定义符合标准ISO 8601definition of a week。
- 第一天是星期一,一直持续到星期日。
- 一周年的第一周包含日历年的第一个星期四。
- 基于周的一年有 52 周或 53 周。
- 日历年的第一天/最后几天可能出现在基于上一周/下一周的年份中。
请注意,确定一周需要确定日期。确定日期需要时区。对于任何给定的时刻,日期在全球范围内因区域而异。因此,如上所示,请清楚您对时区 (ZoneId) 的使用。换句话说,周数是上下文相关的;这取决于特定区域的日期。
在ZonedDateTime::get 中访问TemporalField。 IsoFields 类定义了您需要的常量。
int week = zdt.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) ;
int weekBasedYear = zdt.get( IsoFields.WEEK_BASED_YEAR ) ;
更好的是,将ThreeTen-Extra 库添加到您的项目中以使用YearWeek 类。
org.threeten.extra.YearWeek yw = YearWeek.from( zdt ) ;
唯一标识一周,但对于具有连续两年的日子的周来说,这不是真的。
这是我在 2014 年最后一周得到的一个例子。
2014 年 12 月 27 日星期六 年份:2014 周:52
在标准周中,2014-12-27 是第 52 周。
YearWeek.from( LocalDate.parse( "2014-12-27" ) ).toString()
2014-W52
2014 年底恰好在接下来的周年(2015 年)。
YearWeek.from( LocalDate.parse( "2014-12-31" ) ).toString()
2015-W01
您可以比较YearWeek。调用equals、isBefore 或isAfter 方法。
boolean sameYearWeek = YearWeek.from( someZdt ).equals( YearWeek.from( otherZdt ) )
术语
因此,请确保在您的文档、代码 cmets 和讨论中,始终区分日历年和基于周的年。永远不要说“年份”,因为那是非常模棱两可的。
加上财政年度会更加混乱。有些行业对年份和季节等有自己的定义。所以要小心你的条款。
注意日历软件设置
永远不要假设周数的定义。请确保此类数字的来源与您的星期定义相同,例如 ISO 8601 定义。
例如,macOS 的 Calendar app supplied by Apple 默认为“公历”日历定义的星期。至于这意味着什么,我不知道,因为我找不到任何关于他们的意图/定义的文档。对于 ISO 8601 周,您必须change a setting away from default。
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。
从哪里获得 java.time 类?