iOS 日期上的 SQLite 使用系统时区运行,即使应用程序的默认时区已设置
SQLite on iOS date functions using system timezone even though default timezone for the app has been set
我正在开发一个用户可以登录的应用程序和一个可能位于不同时区的站点 select。因为应用程序显示与该站点相关的数据,所以我决定通过 NSTimeZone.setDefaultTimeZone 将应用程序的默认时区设置为站点时区。这很好用,除非我 select 通过 FMDB 从我们的 sqlite 数据库中获取数据(我认为 FMDB 与它没有任何关系)并使用 strftime 和 'localtime'。虽然我们的数据使用纪元在 UTC 中按分钟存储,但我们经常需要在当地时区按天、工作日或月份显示总和。例如,按工作日获取平均值:
select strftime('%w',datetime(epoch,'localtime')),avg(value)
from values
where siteId = 'x'
group by 1
order by 2 desc
它使用的 'localtime' 是系统本地时间,而不是所有 NSDate 调用都遵循默认时区的应用程序的默认时区。除了本地时间和 UTC 之外,strftime 没有任何其他时区选项,并且当前的解决方法非常慢,需要多次 SQL 往返,这应该很容易在上面的 1 个查询中处理。
谁能告诉我 iOS 上的 sqlite 是如何确定 'localtime' 的?有没有办法强制它使用不同的默认时区?
如您所见,SQLite 不使用 NSDate
或应用程序的本地时区。 datetime
函数使用 修饰符 进行转换。假设您有一个存储为 GMT 的数据库(我认为您的应用就是这种情况):
sqlite> create table mytable (id int, time datetime);
sqlite> insert into mytable values (1, CURRENT_TIMESTAMP);
sqlite> select time from mytable;
2016-06-24 19:05:36 <- THIS IS GMT
sqlite> select datetime(time, 'localtime') from mytable;
2016-06-24 15:05:36 <- THIS IS LOCAL TIME
在此示例(和您的示例)中,'localtime' 是 修饰符 。来自 sqlite 文档:
Modifiers
The time string can be followed by zero or more modifiers that alter
date and/or time. Each modifier is a transformation that is applied to
the time value to its left. Modifiers are applied from left to right;
order is important. The available modifiers are as follows.
- NNN days
- NNN hours
- NNN minutes
- NNN.NNNN seconds
- NNN months
- NNN years
- start of month
- start of year
- start of day
- weekday N
- unixepoch
- localtime
- utc
所以不能直接转换为本地值。但是,因为您可以使用这些 修改器 您的应用程序可以从 NSDate 获取本地 GMT 偏移量:
if let myZone = NSTimeZone(abbreviation: "EST")
{
NSTimeZone.setDefaultTimeZone(myZone)
var offset = (myZone.secondsFromGMT)/3600 as Int
var offsetModifer = "\(offset) hours"
}
然后你可以这样执行你的 sqlite 查询(使用 offsetModifer
构建查询,在此处的示例中转换为 -4 hours
:
sqlite> select datetime(time, '-4 hours') from mytable;
2016-06-24 15:05:36
我正在开发一个用户可以登录的应用程序和一个可能位于不同时区的站点 select。因为应用程序显示与该站点相关的数据,所以我决定通过 NSTimeZone.setDefaultTimeZone 将应用程序的默认时区设置为站点时区。这很好用,除非我 select 通过 FMDB 从我们的 sqlite 数据库中获取数据(我认为 FMDB 与它没有任何关系)并使用 strftime 和 'localtime'。虽然我们的数据使用纪元在 UTC 中按分钟存储,但我们经常需要在当地时区按天、工作日或月份显示总和。例如,按工作日获取平均值:
select strftime('%w',datetime(epoch,'localtime')),avg(value)
from values
where siteId = 'x'
group by 1
order by 2 desc
它使用的 'localtime' 是系统本地时间,而不是所有 NSDate 调用都遵循默认时区的应用程序的默认时区。除了本地时间和 UTC 之外,strftime 没有任何其他时区选项,并且当前的解决方法非常慢,需要多次 SQL 往返,这应该很容易在上面的 1 个查询中处理。
谁能告诉我 iOS 上的 sqlite 是如何确定 'localtime' 的?有没有办法强制它使用不同的默认时区?
如您所见,SQLite 不使用 NSDate
或应用程序的本地时区。 datetime
函数使用 修饰符 进行转换。假设您有一个存储为 GMT 的数据库(我认为您的应用就是这种情况):
sqlite> create table mytable (id int, time datetime);
sqlite> insert into mytable values (1, CURRENT_TIMESTAMP);
sqlite> select time from mytable;
2016-06-24 19:05:36 <- THIS IS GMT
sqlite> select datetime(time, 'localtime') from mytable;
2016-06-24 15:05:36 <- THIS IS LOCAL TIME
在此示例(和您的示例)中,'localtime' 是 修饰符 。来自 sqlite 文档:
Modifiers
The time string can be followed by zero or more modifiers that alter date and/or time. Each modifier is a transformation that is applied to the time value to its left. Modifiers are applied from left to right; order is important. The available modifiers are as follows.
- NNN days
- NNN hours
- NNN minutes
- NNN.NNNN seconds
- NNN months
- NNN years
- start of month
- start of year
- start of day
- weekday N
- unixepoch
- localtime
- utc
所以不能直接转换为本地值。但是,因为您可以使用这些 修改器 您的应用程序可以从 NSDate 获取本地 GMT 偏移量:
if let myZone = NSTimeZone(abbreviation: "EST")
{
NSTimeZone.setDefaultTimeZone(myZone)
var offset = (myZone.secondsFromGMT)/3600 as Int
var offsetModifer = "\(offset) hours"
}
然后你可以这样执行你的 sqlite 查询(使用 offsetModifer
构建查询,在此处的示例中转换为 -4 hours
:
sqlite> select datetime(time, '-4 hours') from mytable;
2016-06-24 15:05:36