Mar*_*nha 3 java mysql jpa date jodatime
我的 MySQL 数据库中有一个表,它有一个日期列:
+-------------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| type | varchar(50) | NO | | NULL | |
| expiration | date | NO | | NULL | |
Run Code Online (Sandbox Code Playgroud)
我正在使用带有 JPA 的 MySQL 来保存日期。我有一个功能,用户可以选择一个最终的日期范围,它会得到所有的日期。
查看此代码(带有一堆 SYSO)以尝试查看发生了什么...
@Override
protected DateTime nextReference(DateTime reference) {
System.out.println("Reference: " + reference.toString("dd-MM-YYYY"));
DateTime plus = reference.plusMonths(1);
System.out.println("One month from now: " + plus.toString("dd-MM-YYYY"));
DateTime result = plus.withDayOfMonth(reference.getDayOfMonth());
System.out.println("Final: " + result.toString("dd-MM-YYYY"));
return result;
}
Run Code Online (Sandbox Code Playgroud)
这部分,结果很好:
Reference: 10-01-2017
One month from now: 10-02-2017
Final: 10-02-2017
Reference: 10-02-2017
One month from now: 10-03-2017
Final: 10-03-2017
Reference: 10-03-2017
One month from now: 10-04-2017
Final: 10-04-2017
Reference: 10-04-2017
One month from now: 10-05-2017
Final: 10-05-2017
Reference: 10-05-2017
One month from now: 10-06-2017
Final: 10-06-2017
Reference: 10-06-2017
One month from now: 10-07-2017
Final: 10-07-2017
Reference: 10-07-2017
One month from now: 10-08-2017
Final: 10-08-2017
Reference: 10-08-2017
One month from now: 10-09-2017
Final: 10-09-2017
Reference: 10-09-2017
One month from now: 10-10-2017
Final: 10-10-2017
Reference: 10-10-2017
One month from now: 10-11-2017
Final: 10-11-2017
Reference: 10-11-2017
One month from now: 10-12-2017
Final: 10-12-2017
Reference: 10-12-2017
One month from now: 10-01-2018
Final: 10-01-2018
Run Code Online (Sandbox Code Playgroud)
好的,现在让我们转到保存部分:
@Transactional
private void saveTransactions(List<Transaction> transactions) {
for (Transaction t : transactions) {
System.out.println("Saving: " + t.getExpiration().toString("dd-MM-YYYY"));
Transaction saved = dao.save(t);
System.out.println("Saved: " + saved.getExpiration().toString("dd-MM-YYYY"));
}
}
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,我也放了一些行来调试这个......在我继续输出之前,检查一下 DAO:
public T save(T entity) {
entityManager.persist(entity);
return entity;
}
Run Code Online (Sandbox Code Playgroud)
没什么大不了的......输出:
Saving: 10-02-2017
Saved: 10-02-2017
Saving: 10-03-2017
Saved: 10-03-2017
Saving: 10-04-2017
Saved: 10-04-2017
Saving: 10-05-2017
Saved: 10-05-2017
Saving: 10-06-2017
Saved: 10-06-2017
Saving: 10-07-2017
Saved: 10-07-2017
Saving: 10-08-2017
Saved: 10-08-2017
Saving: 10-09-2017
Saved: 10-09-2017
Saving: 10-10-2017
Saved: 10-10-2017
Saving: 10-11-2017
Saved: 10-11-2017
Saving: 10-12-2017
Saved: 10-12-2017
Run Code Online (Sandbox Code Playgroud)
如你所见……应该没问题吧?一切都在 10 日。
在我再次继续之前,请检查模型和转换器:
//Attribute
@Convert(converter = JpaDateConverter.class)
private DateTime expiration;
//Converter
public class JpaDateConverter implements AttributeConverter<DateTime, Date> {
@Override
public Date convertToDatabaseColumn(DateTime objectValue) {
return objectValue == null ? null : new Date(objectValue.getMillis());
}
@Override
public DateTime convertToEntityAttribute(Date dataValue) {
return dataValue == null ? null : new DateTime(dataValue);
}
}
Run Code Online (Sandbox Code Playgroud)
现在看看我的数据库:
mysql> select expiration from tb_transaction where notes = 3 and year(expiration
) = 2017;
+------------+
| expiration |
+------------+
| 2017-01-10 |
| 2017-02-10 |
| 2017-03-09 |
| 2017-04-09 |
| 2017-05-09 |
| 2017-06-09 |
| 2017-07-09 |
| 2017-08-09 |
| 2017-09-09 |
| 2017-10-09 |
| 2017-11-10 |
| 2017-12-10 |
+------------+
12 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
出于一些奇怪的、神秘的原因,有些日期保存在 9 号而不是 10 号!!
没有警告,没有 MySQL 驱动程序错误或什么都没有。
请帮助伙计们!
编辑交易类:
@Entity
@Table(name = "tb_transaction")
public class Transaction implements Cloneable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Enumerated(STRING)
private TransactionType type;
@Convert(converter = JpaDateConverter.class)
private DateTime expiration;
Run Code Online (Sandbox Code Playgroud)
使用JPA 2.2来支持java.time。
使用 Java 中的仅日期类来处理 SQL 中的仅日期值。
LocalDate // Represent a date-only, without a time-of-day and without a time zone.
.now( // Get today's date…
ZoneId.of( "Africa/Tunis" ) // …as seen in the wall-clock time used by the people of a particular region.
) // Returns a `LocalDate` object.
.plusMonths( 1 ) // Returns another `LocalDate` object, per immutable objects pattern.
Run Code Online (Sandbox Code Playgroud)
JPA 2.2现在支持现代java.time类。不再需要使用 Joda-Time。
千万不能使用java.sql.Date。该类假装仅表示日期,但实际上将时间设置为 UTC,因为要继承的可怕设计决定java.util.Date(尽管名称表示日期和时间以及零偏移量)对于 UTC 本身)。这些遗留类是一个可怕的可悲的烂摊子。Sun、Oracle 和 JCP 社区都在多年前随着 JSR 310 的采用而放弃了这些课程,您也应该如此。
LocalDate该LocalDate级表示没有时间的天,没有一个日期,只值时区或偏移从-UTC。
时区对于确定日期至关重要。对于任何给定时刻,日期因地区而异。例如,在法国巴黎午夜过后几分钟是新的一天,而在魁北克蒙特利尔仍然是“昨天” 。
如果未指定时区,JVM 会隐式应用其当前默认时区。该默认值可能会在运行时随时更改(!),因此您的结果可能会有所不同。最好将您想要/预期的时区明确指定为参数。如果关键,请与您的用户确认该区域。
以、、 或等格式指定正确的时区名称。永远不要使用 2-4 个字母的缩写,例如或因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。Continent/RegionAmerica/MontrealAfrica/CasablancaPacific/AucklandESTIST
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
Run Code Online (Sandbox Code Playgroud)
如果您想使用 JVM 的当前默认时区,请询问它并作为参数传递。如果省略,代码读起来会变得模棱两可,因为我们不确定您是否打算使用默认值,或者您是否像许多程序员一样没有意识到这个问题。
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Run Code Online (Sandbox Code Playgroud)
或指定日期。您可以通过数字设置月份,对于 1 月至 12 月,合理编号为 1-12。
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Run Code Online (Sandbox Code Playgroud)
或者,更好的是使用Month预定义的枚举对象,一年中的每个月一个。提示:Month在整个代码库中使用这些对象而不仅仅是整数,以使您的代码更具自文档性、确保有效值并提供类型安全。同上Year& YearMonth。
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
Run Code Online (Sandbox Code Playgroud)
显然,您希望从一个日期开始,并在一个月后将其作为日期范围。
LocalDate monthLater = ld.plusMonths( 1 ) ;
Run Code Online (Sandbox Code Playgroud)
从 JDBC 4.2 开始,您的 JDBC 驱动程序需要支持一些关键的java.time类,例如LocalDate.
请注意以下ThreeTen-Extra的链接。LocalDateRange如果您对日期范围做了很多工作,您可能会发现那里的课程很方便。
该java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat。
要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310。
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
您可以直接与您的数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*
从哪里获得 java.time 类?
该ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如Interval,YearWeek,YearQuarter,和更多。
| 归档时间: |
|
| 查看次数: |
4480 次 |
| 最近记录: |