tl;博士
LocalDateTime.parse(
"2015-08-18 00:00:00".replace( " " , "T" ) // Convert input string to comply with ISO 8601 standard format, replacing SPACE in the middle with a `T`.
).plus(
Duration.ofDays( 31 ) // If you meant ( 31 * 24-hours ).
// Period.ofDays( 31 ) // If you meant 31 calendar-days.
// Period.ofMonths( 1 ) // If you meant a calendar-month.
) // Returns a fresh `LocalDateTime` object, distinct from original, per Immutable Objects pattern.
.toString() // Generate a string in standard ISO 8601 format to textually represent this object’s value.
2015-09-18T00:00
条款
这里的“偏移”一词是一个糟糕的术语选择。该词在日期时间处理中具有特定含义:时区来自 UTC 的小时、分钟和秒数。请参阅UTC offset 的维基百科条目。
您似乎更关心的是与时间轴无关的时间跨度。在 java.time 类中,如果以小时-分钟-秒为单位,此类跨度称为 Duration,如果以年-月-日为单位,则称为 Period。
java.time
现代方法使用 java.time 类取代了麻烦的旧日期时间类,例如 Date/Calendar。
Duration
将您的时间跨度从毫秒数转换为 Duration 对象。
Duration d = Duration.ofMillis( 2_678_400_000L );
这恰好是 744 小时。
d.toString(): PT744H
出于好奇,我检查了 744 小时内的天数,如果我们将“天”定义为 24 小时的块。
d.toDaysPart(): 31
看来您确实打算一个月或 31 天。无论哪种方式,Java 都有相应的类。
如果你真的想要:(31 * 24 小时),那么请使用Duration。但是用更多的自记录代码构造Duration 对象。
Duration d = Duration.ofDays( 31 ) ; // Exact same effect as `Duration.ofMillis( 2_678_400_000L )` but more clear as to your intention.
ISO 8601
您的输入字符串几乎符合日期时间格式的 ISO 8601 标准。 java.time 类在解析/生成字符串时默认使用标准格式。
将您的字符串转换为符合要求。将中间的空格替换为T。
String input = "2015-08-18 00:00:00".replace( " " , "T" ) ;
2015-08-18T00:00:00
LocalDateTime
将您的输入解析为LocalDateTime,因为您的输入缺少offset-from-UTC 或time zone 的指示符。
LocalDateTime ldt = LocalDateTime.parse( input ) ;
ldt.toString(): 2015-08-18T00:00
添加您的Duration 对象以获得新的LocalDateTime。 java.time 类使用immutable objects,因此原始对象保持不变。
LocalDateTime thirtyOneTimes24HoursLaterLdt = ldt.plus( d ) ; // Adding a span-of-time to our `LocalDateTime` object to get another `LocalDateTime` object.
thirtyOneTimes24HoursLaterLdt.toString(): 2015-09-18T00:00
请注意,LocalDateTime 确实不代表一个实际的时刻,即时间线上的一个特定点。如果没有时区的上下文或与 UTC 的偏移,这只是关于大约 26-27 小时范围内的潜在时刻的粗略概念。
ZonedDateTime
如果您确定您的输入字符串旨在表示特定区域中的某个时刻,请应用 ZoneId 以获取 ZonedDateTime 对象(实际时刻)。
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ; // Now we have determined an actual moment, a point on the timeline.
zdt.toString(): 2015-08-18T00:00+12:00[太平洋/奥克兰]
如果您不关心日期(日历上的整天),可以添加您的 Duration。
ZonedDateTime thirtyOneTimes24HoursLaterZdt = zdt.plus( d ) ;
thirtyOneTimes24HoursLaterZdt.toString(): 2015-09-18T00:00+12:00[太平洋/奥克兰]
如果您的业务逻辑确实是日历上的 31 天,请使用 Period。
ZonedDateTime thirtyOneDaysLater = zdt.plus( Period.ofDays( 31 ) ) ;
thirtyOneDaysLater.toString(): 2015-09-18T00:00+12:00[太平洋/奥克兰]
如果您的业务逻辑确实打算使用日历月而不是特定天数,请使用不同的Period。该课程根据需要进行调整以处理不同月份的长度(read the doc 并关注that doc’s link)。
ZonedDateTime monthLater = zdt.plus( Period.ofMonths( 1 ) ) ;
monthLater.toString(): 2015-09-18T00:00+12:00[太平洋/奥克兰]
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
使用符合JDBC 4.2 或更高版本的JDBC driver,您可以直接与您的数据库交换java.time 对象。不需要字符串也不需要 java.sql.* 类。
从哪里获得 java.time 类?
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。