如何从 unixtime(integer) 列包含当前日期而不考虑时间的表中选择记录?

Posted

技术标签:

【中文标题】如何从 unixtime(integer) 列包含当前日期而不考虑时间的表中选择记录?【英文标题】:How can I select records from a table where unixtime(integer) column contains the current date without considering the time? 【发布时间】:2018-10-20 08:22:57 【问题描述】:

我在 android SQLite 数据库中有一个包含以下字段的表。

在此,due_date 列是 INTEGER,我只想要在 due_date 不考虑时间匹配今天的日期(当前日期)的记录。

例如:如果我有 3 个值与当前日期匹配,我需要返回所有 3 行

注意:在我的情况下,必须与当前日期而不是当前日期进行比较 时间戳,但我的列类型是 具有 unix-epoch 值的整数。 我的 unix-epoch 示例是“1526565900000”。

我试过了:

 date('now', 'start of day') // not working

 date('now','localtime','start of day') // not working

select strftime('%d', date('now')), name, due_date from task group by due_date;

这也不符合我的要求。

最后根据下面的 cmets 我 更改了我所有的日期时间和 timestamp 列到 INTEGER 中以存储为 unix-epoch 值,然后我的所有列都在时间戳中。

【问题讨论】:

您必须将值存储在数据库中的supported date formats 之一中。 这会让你头疼。请以 ISO 格式存储您的时间戳。 @CL。 - 感谢您的回复,android-sqlite 不支持时间戳格式? @TimBiegeleisen 感谢您的回复,是否可以存储在 android-sqlite 的 datetime 类型中? 这是第三个format,正如 CL 在他的第一条评论中指出的那样:“INTEGER 作为 Unix 时间,自 1970-01-01 00:00:00 UTC 以来的秒数。” 【参考方案1】:

tl;博士

myPreparedStatement.setObject(                        // Generally best to use Prepared Statement, to avoid SQL Injection risk.
    1 ,                                               // Specify which placeholder `?` in your SQL statement.
    LocalDate.now( ZoneId.of( "Pacific/Auckland" ) )  // Determine today’s date as seen in the wall-clock time used by the people of a certain continent/region (a time zone).
    .atStartOfDay( ZoneId.of( "Pacific/Auckland" ) )  // Determine the first moment of the day on that date in that zone. Not always 00:00:00.
    .toInstant()                                      // Adjust that first moment of the day in that zone to the wall-clock-time of UTC.
    .getEpochSecond()                                 // Get a count of whole seconds since the epoch reference of 1970-01-01T00:00:00Z. 
)

java.time

现代方法使用 java.time 类取代了麻烦的旧旧日期时间类。

在此,due_date 列是 INTEGER,我只想要在 due_date 中单独匹配今天日期(当前日期)的记录,而不考虑时间。

LocalDate

LocalDate 类表示没有时间和时区的仅日期值。

时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因区域而异。例如,Paris France 中午夜后几分钟是新的一天,而 Montréal Québec 中仍然是“昨天”。

如果没有指定时区,JVM 会隐式应用其当前的默认时区。该默认值可能随时更改,因此您的结果可能会有所不同。最好将您想要/预期的时区明确指定为参数。

continent/region 的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
LocalDate today = LocalDate.now( z ) ;

如果你想使用 JVM 当前的默认时区,请求它并作为参数传递。如果省略,则隐式应用 JVM 的当前默认值。最好是明确的,因为默认值可能会在任何时候在运行时被 JVM 中任何应用程序的任何线程中的任何代码更改。

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

纪元秒数

我们需要将该日期转换为一个数字,即自 UTC 中 1970 年第一刻的 epoch reference 以来的秒数。

为此,我们需要抓住一天中的第一刻。让 java.time 确定第一个时刻。不要假设一天从 00:00:00 开始。夏令时 (DST) 等异常情况意味着一天可能从另一个时间开始,例如 01:00:00。指定时区以获取ZonedDateTime 对象。

ZonedDateTime zdt = today.atStartOfDay( z ) ;

我们必须从我们的区域适应 UTC。最简单的方法是提取Instant。默认情况下,Instant 类始终采用 UTC。

Instant instant = zdt.toInstant() ;  // Adjust from our zone to UTC.

获取自纪元以来的秒数。

long secondsSinceEpoch = instant.getEpochSecond() ;  

作为一种捷径,我们可以直接从 ZonedDateTime 类中请求秒数。但我想明确表示,我们正在努力从特定时区调整为 UTC。

long startSecondsSinceEpoch = zdt.toEpochSecond() ;  // Shortcut for adjusting from time zone to UTC, and then getting count of seconds since epoch.

我们还需要时间范围的结束,以查找日期为今天的所有记录。我们将使用第二天的第一个时刻。这遵循了时间跨度的半开放定义的通常做法。在 Half-Open 中,开头是 inclusive 而结尾是 exclusive

long stopSecondsSinceEpoch = ld.plusDays( 1 ).atStartOfDay( z ).toEpochSecond() ;

SQL

现在我们已经为 SQL 语句做好了准备。通常最好养成使用准备好的语句的习惯。

String sql = "SELECT when FROM tbl WHERE when >= ? AND when < ? ; " ;
…
myPreparedStatement.setObject( 1 , startSecondsSinceEpoch ) ;
myPreparedStatement.setObject( 2 , stopSecondsSinceEpoch ) ;  

关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

从哪里获得 java.time 类?

Java SE 8Java SE 9Java SE 10 及更高版本 内置。 标准 Java API 的一部分,带有捆绑实现。 Java 9 添加了一些小功能和修复。 Java SE 6Java SE 7 大部分 java.time 功能都在ThreeTen-Backport 中向后移植到 Java 6 和 7。 Android java.time 类的 Android 捆绑包实现的更高版本。 对于早期的 Android (ThreeTenABP 项目适应 ThreeTen-Backport(如上所述)。见How to use ThreeTenABP…

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuarter 和more。

【讨论】:

【参考方案2】:

第 1 步:首先我将列类型更改为 int 为 @CL mentioned,之前它被声明为日期时间和时间戳。

第 2 步:然后按照@pskink 在 cmets 中的说明,以秒为单位(即 10 位)插入所有日期时间值。

第 3 步:要以秒为单位获取当前日期的开始和结束值,我使用了以下 java 代码。

//getCurrentDateTimeInMilliseconds
    public void getCurrentDateTimeInMilliseconds() 
        Date todayStart = new Date();
        Date todayEnd = new Date();

        todayStart.setHours(0);
        todayStart.setMinutes(0);
        todayStart.setSeconds(0);
        todayEnd.setHours(23);
        todayEnd.setMinutes(59);
        todayEnd.setSeconds(59);
        long endTime = todayEnd.getTime();
    

使用它,您可以像这样获取当天的开始和结束值

todayStart.getTime()

它将以毫秒为单位返回值,即 13 位值,将其转换为秒,只需像这样除以 1000,

long startDateInSeconds = todayStart.getTime/1000;
long startDateInSeconds = todayEnd.getTime/1000;

并在我的情况下根据要求在sqlite查询中使用这些值,查询如下:

String query = "select * from task where due_date>" + startDateInSeconds + " and due_date<" + startDateInSeconds;

然后像这样在databasehelper类的方法中传递查询,

Cursor cursor = databasehelper.getData(query);

在 DatabaseHelper.java(应该扩展 SQLiteOpenHelper 类)文件中执行以下代码:

public Cursor getData(String query) 
        SQLiteDatabase sqLiteDatabase = this.getReadableDatabase();
        return sqLiteDatabase.rawQuery(query, null);
    

终于在@pskink的帮助下搞定了,感谢你们的cmets帮了我很多。

像这样存储在我的数据库中的数据。

【讨论】:

【参考方案3】:
SELECT * FROM your table name where due_date BETWEEN date('now') AND strftime('%Y-%m-%d', due_date)

【讨论】:

感谢您的回答,但我需要提取列到期日期的值,该怎么做? 抱歉,它不起作用,我将我的所有列更改为 Integer 以存储 unix 纪元时间,这工作正常,但仍未得到我的要求的查询,谢谢。 @pskink 首先感谢四个idea,它促使我学习了一些有趣的概念,实际上不知道查询来获取与今天日期匹配的整数(unix_epoch)值的due_date记录,请帮助我在这。 @pskink 试过这个 "select * from task where due_date>1525910400 and due_date 0 行返回自:select * from task where due_date>1525910400 and due_date @Shiva 查询正常,你的 sql db 数据不正常

以上是关于如何从 unixtime(integer) 列包含当前日期而不考虑时间的表中选择记录?的主要内容,如果未能解决你的问题,请参考以下文章

有A和B两个顺序表,数据都为从小到大排列,如何把它们合并从一个顺序表C

Hive表日期列值转换

如何将子查询包含到内部联接中?

将结果列从函数集成到主查询

如何比较不同表中的两个INTEGER列?

BigQuery:如何将我的一列的类型从 INTEGER 更改为 STRING?