如何将带偏移的日志时间统一转换为UTC+1时区?
日志设备数据时区转换解决方案
问题背景
处理日志设备数据时遇到时区转换难题:多台设备读数时区被误设为GMT+1或GMT+2(无夏令时切换),需统一转换为UTC+1以保证数据可比性。已构建包含date_time(字符型)、temp、loggerID、timezone(GMT+1/GMT+2)的DataFrame,尝试以下方法均失败:
- POSIXct条件指定时区:
dat_temp <- dat_temp %>% mutate(date_time_set = if_else(timezone == "GMT+1", as.POSIXct(date_time, format = "%Y-%m-%d %H:%M:%S", tz = "GMT+1"), as.POSIXct(date_time, format = "%Y-%m-%d %H:%M:%S", tz = "GMT+2")))
R不支持直接用偏移值指定时区,需用地区标识符(如Europe/Paris),但这类地区会自动应用夏令时,不符合需求。
- lubridate::ymd_hms尝试相同逻辑:
dat_temp <- dat_temp %>% mutate(date_time_set = if_else(timezone == "GMT+1", ymd_hms(dat_temp$date_time, tz = "GMT+1"), ymd_hms(dat_temp$date_time, tz = "GMT+2")))
遇到同样问题,无法指定固定偏移时区。
- 先设为UTC再手动调整:
dat_temp <- dat_temp %>% mutate(date_time_posix = as.POSIXct(date_time, format = "%Y-%m-%d %H:%M:%S", tz = "UTC"), date_time_corr = if_else(timezone == "GMT+2", date_time_posix - (1*60*60), date_time_posix))
尝试lubridate::with_tz()和force_tz()也未成功。
核心问题
- 是否存在可直接指定固定偏移时区(如GMT+1、UTC+2)、无需自动处理夏令时的方法或函数?
- 若不存在,能否将所有数据统一转换为UTC+1后,保存为无时区格式避免其他用户误改?
解决方案
问题1:直接指定固定偏移时区的方法
R支持使用Etc/GMT±X系列时区标识符(注意符号反向:Etc/GMT-1对应UTC+1,Etc/GMT-2对应UTC+2,遵循POSIX标准),这类时区无夏令时切换,是固定偏移。
方法示例(lubridate + dplyr):
library(lubridate) library(dplyr) dat_temp <- dat_temp %>% mutate( # 按设备时区转换为对应固定偏移时间 date_time_tz = case_when( timezone == "GMT+1" ~ ymd_hms(date_time, tz = "Etc/GMT-1"), timezone == "GMT+2" ~ ymd_hms(date_time, tz = "Etc/GMT-2") ), # 统一转换为UTC+1 date_time_utc1 = with_tz(date_time_tz, tz = "Etc/GMT-1") )
方法示例(基础R):
# 转换为对应固定偏移时区的时间 dat_temp$date_time_tz <- ifelse( dat_temp$timezone == "GMT+1", as.POSIXct(dat_temp$date_time, format = "%Y-%m-%d %H:%M:%S", tz = "Etc/GMT-1"), as.POSIXct(dat_temp$date_time, format = "%Y-%m-%d %H:%M:%S", tz = "Etc/GMT-2") ) # 统一转换为UTC+1 dat_temp$date_time_utc1 <- as.POSIXct( format(dat_temp$date_time_tz, tz = "Etc/GMT-1"), format = "%Y-%m-%d %H:%M:%S", tz = "Etc/GMT-1" )
问题2:转换为UTC+1后保存为无时区格式
若要彻底避免时区干扰,可采用两种方式:
方法1:转换为字符型(最安全,无歧义)
dat_temp <- dat_temp %>% mutate(date_time_utc1_char = format(date_time_utc1, "%Y-%m-%d %H:%M:%S")) # 导出时直接使用字符型列 write.csv(dat_temp, "log_data_utc1.csv", row.names = FALSE)
方法2:转换为无时区的POSIXct
dat_temp <- dat_temp %>% mutate(date_time_utc1_notz = as.POSIXct(format(date_time_utc1, "%Y-%m-%d %H:%M:%S"), tz = ""))
此方式下时间对象无附带时区信息,其他用户打开时不会自动转换,但后续操作需明确说明该时间为UTC+1。
数据子集
> dput(dat_temp) structure(list(date_time = c("2021-07-01 00:00:00", "2021-07-01 00:30:00", "2021-07-01 01:00:00", "2021-07-01 01:30:00", "2021-07-01 02:00:00", "2021-07-01 02:30:00", "2021-07-01 03:00:00", "2021-07-01 03:30:00", "2021-07-01 04:00:00", "2021-07-01 04:30:00", "2021-10-16 02:30:00", "2021-10-16 03:00:00", "2021-10-16 03:30:00", "2021-10-16 04:00:00", "2021-10-16 04:30:00", "2021-10-16 05:00:00", "2021-10-16 05:30:00", "2021-10-16 06:00:00", "2021-10-16 06:30:00", "2021-10-16 07:00:00", "2021-10-16 07:30:00", "2021-11-03 00:00:00", "2021-11-03 00:30:00", "2021-11-03 01:00:00", "2021-11-03 01:30:00", "2021-11-03 02:00:00", "2021-11-03 02:30:00", "2021-11-03 03:00:00", "2021-11-03 03:30:00", "2021-11-03 04:00:00", "2021-11-03 04:30:00", "2021-11-03 05:00:00", "2021-11-19 11:00:00", "2021-11-19 11:30:00", "2021-11-19 12:00:00", "2021-11-19 12:30:00", "2021-11-19 13:00:00", "2021-11-19 13:30:00", "2021-11-19 14:00:00", "2021-11-19 14:30:00", "2021-11-19 15:00:00", "2021-11-19 15:30:00", "2021-11-19 16:00:00"), temp = c(16.427, 16.141, 15.951, 15.569, 15.282, 14.996, 14.9, 14.709, 14.517, 14.421, 4.727, 4.623, 4.519, 4.415, 4.311, 4.207, 4.102, 3.998, 3.893, 3.788, 3.683, 2.73, 2.624, 2.624, 2.624, 2.517, 2.517, 2.517, 2.517, 2.624, 2.73, 2.837, 0.674, 0.674, 0.784, 1.112, 1.872, 2.517, 2.943, 3.155, 3.155, 3.049, 2.73), loggerID = c("logger1", "logger1", "logger1", "logger1", "logger1", "logger1", "logger1", "logger1", "logger1", "logger1", "logger2", "logger2", "logger2", "logger2", "logger2", "logger2", "logger2", "logger2", "logger2", "logger2", "logger2", "logger1", "logger1", "logger1", "logger1", "logger1", "logger1", "logger1", "logger1", "logger1", "logger1", "logger1", "logger3", "logger3", "logger3", "logger3", "logger3", "logger3", "logger3", "logger3", "logger3", "logger3", "logger3" ), timezone = c("GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+2", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1", "GMT+1")), row.names = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 142902L, 142903L, 142904L, 142905L, 142906L, 142907L, 142908L, 142909L, 142910L, 142911L, 142912L, 196225L, 196226L, 196227L, 196228L, 196229L, 196230L, 196231L, 196232L, 196233L, 196234L, 196235L, 533387L, 533388L, 533389L, 533390L, 533391L, 533392L, 533393L, 533394L, 533395L, 533396L, 533397L ), class = "data.frame")
内容的提问来源于stack exchange,提问作者Em Laskey
相关产品推荐
相关产品推荐

