在 MySQL 中设置一个表,用于保存特定营业地点的 Activity (例如音乐表演或卡拉 OK)的数据。
所以我的表格看起来像这样:
CREATE TABLE `event_schedule` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`description` varchar(30) DEFAULT NULL,
`event_id` varchar(30) NOT NULL DEFAULT,
`event_date` datetime DEFAULT NULL,
`event_date_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
)
数据库表包含如下行:
| 1 | karoake | aab3223 | 2017-08-15 00:00:00 | 2017-08-15 16:00:00 |
| 2 | comedy | cce8465 | 2017-08-25 00:00:00 | 2017-08-25 19:00:00 |
event_date 也是 UTC 时间格式,也是它所在的 MySQL 服务器的格式。
select now()
将给出 UTC 时间...
具有逻辑设置,使用 Spring JDBC 根据 curdate() 检查特定行是否存在,如下所示:
@Repository
public class EventDao {
private static JdbcTemplate jdbcTemplate = null;
@Autowired
public EventDao(@Qualifier("aDataSource") DataSource dataSource) {
EventDao.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
public static String getEventId() {
SqlRowSet eventRowSet = null;
String eventId = "";
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
dateInUTC = formatter.format(new Date());
eventRowSet = jdbcTemplate.queryForRowSet(
"select * from event_schedule where (event_date=CURDATE() or event_date=?)",
new Object[] { dateInUTC });
if (eventRowSet != null && eventRowSet.next()) {
eventId = rst.getString("event_id");
}
return eventId;
}
}
用于检查事件是否正在进行的类:
public class EventProcessor {
public static String getEventStatus() {
String eventId = getEventId();
if (eventId != null) {
return "Event Started";
}
else {
return "Event not Started"
}
// TODO: Need to incorporate for two hours after its over.
// "Event Ended"
}
}
当仅依赖于 UTC 中的 event_date 的要求很简单时,该系统似乎可以正常工作:
2017-08-15 00:00:00
新用例/问题:
如果客户端应用程序连接到此 Web 服务并且情况是:
Activity 于 2017 年 8 月 15 日 19:00:00 开始(假设现在是太平洋标准时间晚上 7:00)我该如何设置:
- 服务是否在 2017-08-14 00:00 至 2017-08-15 18:59:59 期间返回“Activity 未开始”?
意思是,从同一日期的午夜到开始前一分钟?
<小时/>- 服务是否会在 Activity 结束两小时后返回“Activity 结束”?
我的许多连接到此 Web 服务的客户端应用程序可能位于西海岸 (PST)、中部 (CST) 或东部 (EST)。
- 为它们进行时间转换的最佳方法是什么(因为我在 MySQL 数据库中使用 UTC 日期时间,而 MySQL 数据库本身就是 UTC)?
最佳答案
这个问题已经在 Stack Overflow 上从不同角度得到了多次解决。因此,请搜索更多信息。
简单地说...
我不使用 Spring,因此这里有基本的 JDBC 来指导您。
仅使用 java.time 类。避免麻烦的旧遗留日期时间类,例如 Date
、Calendar
和 java.sql
类。
如果您的日期时间是历史上过去的时刻或即将到来的特定时刻,则将其存储在 UTC 中。以 UTC 时间查询。显示在用户预期的时区。
如果安排的时间超过几周,您可能需要使用不带时区或偏移量的日期时间值,因为政治家经常在几乎没有提前通知的情况下重新定义时区。我在这里忽略它。
指定proper time zone name格式为大洲/地区
,如America/Montreal
, Africa/Casablanca
,或太平洋/奥克兰
。切勿使用 3-4 个字母的缩写,例如 PST
或 IST
,因为它们不是真正的时区,不是标准化的,甚至不是唯一的( !)。
ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
LocalDate startDate = LocalDate.of( 2017 , 8 , 15 ) ;
LocalTime startTime = LocalTime.of( 19 , 0 ) ;
ZonedDateTime start = ZonedDateTime.of( startDate , startTime , z ) ;
Duration d = Duration.ofHours( 2 ) ;
ZonedDateTime stop = start.plus( d ) ;
如果您想存储Duration
,请调用toString
并使用标准ISO 8601存储其生成的字符串。格式。
半开放逻辑
使用半开放逻辑,其中开始是包含,而结束是排除。这完全避免了“从同一日期的午夜到开始前一分钟?”的困惑。
String sql = "INSERT INTO event ( start , stop , duration , … ) VALUES ( ? , ? , ? , ...) ;" ;
… make prepared statement
myPreparedStatement.setObject( 1 , start.toInstant() ) ;
myPreparedStatement.setObject( 2 , stop.toInstant() ) ;
myPreparedStatement.setObject( 3 , duration.toString() ) ;
myPreparedStatement.setObject( … , … ) ;
查询类似。
String sql = "SELECT start , stop , duration , pkey , … FROM event WHERE pkey = ? ;" ) ;
… execute query, get ResultSet
… loop the resulting rows
Instant start = myResultSet.get( 1 , Instant.class ) ;
Instant stop = myResultSet.get( 2 , Instant.class ) ;
Duration d = Duration.parse( myResultSet.getString( 3 ) ) ;
与当前时刻进行比较。
Instant
类代表UTC中时间线上的一个时刻。分辨率为nanoseconds (最多九 (9) 位小数)。
Instant now = Instant.now() ;
Boolean eventScheduled = now.isBefore( start ) ;
Boolean eventOccurring = ( ! now.isBefore( start ) ) && now.isBefore( stop ) ;
Boolean eventExpired = ! now.isBefore( stop ) ; // "Not before stop" means either (a ) now is exactly the moment of expiration (using half-open logic we consider that past), or (b) now is later, after the moment of expiration.
如果要查询尚未开始的事件:
String sql = "SELECT start , stop , duration , pkey , … FROM event WHERE start > ? ; " ) ; // Find events starting after the passed moment.
…
myPreparedStatement.setObject( 1 , Instant.now() ) ;
上面的代码假设您的 JDBC 驱动程序符合 JDBC 4.2 或更高版本,以直接支持 java.time 类型。
关于java - 如何在 Java 中检查日期时间之前和之后的日期,以了解 MySQL 中的 UTC 日期,但对于多个时区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46597505/