如何从 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/Montreal
、Africa/Casablanca
或Pacific/Auckland
。切勿使用 3-4 个字母的缩写,例如 EST
或 IST
,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。
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.Date
、Calendar
和 SimpleDateFormat
。
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 8、Java SE 9、Java SE 10 及更高版本 内置。 标准 Java API 的一部分,带有捆绑实现。 Java 9 添加了一些小功能和修复。 Java SE 6 和 Java 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 的试验场。您可以在这里找到一些有用的类,例如Interval
、YearWeek
、YearQuarter
和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) 列包含当前日期而不考虑时间的表中选择记录?的主要内容,如果未能解决你的问题,请参考以下文章