java - 如何在 Java 中检查日期时间之前和之后的日期,以了解 MySQL 中的 UTC 日期,但对于多个时区?

标签 java mysql date datetime utc

在 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)我该如何设置:

  1. 服务是否在 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 类。避免麻烦的旧遗留日期时间类,例如 DateCalendarjava.sql 类。

    如果您的日期时间是历史上过去的时刻或即将到来的特定时刻,则将其存储在 UTC 中。以 UTC 时间查询。显示在用户预期的时区。

    如果安排的时间超过几周,您可能需要使用不带时区或偏移量的日期时间值,因为政治家经常在几乎没有提前通知的情况下重新定义时区。我在这里忽略它。

    指定proper time zone name格式为大洲/地区,如America/Montreal , Africa/Casablanca ,或太平洋/奥克兰。切勿使用 3-4 个字母的缩写,例如 PSTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的( !)。

    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/

    相关文章:

    php - 错误的字符串值 : '\xCC_a' for column

    java - MongoDB 中基于日期排序

    java - 如何从 HashMap 的数组中获取索引?

    sql - 如何在两个独立的 MySQL 连接之间执行 SQL 语句?

    java - 使用自定义比较器对基元数组进行排序,而不转换为对象

    php - 变量名放入 CREATE TABLE IF NOT EXISTS 在 php 中

    matlab - 如何根据两列对矩阵进行排序

    javascript - Jquery 检查日期是否为当前日期或已过日期

    java - java中的路径问题

    java - 在 Java 中生成 CPU 负载