如何在 R 中解析年 + 周数?

Posted

技术标签:

【中文标题】如何在 R 中解析年 + 周数?【英文标题】:How to Parse Year + Week Number in R? 【发布时间】:2012-03-11 22:23:46 【问题描述】:

有没有一种好方法可以在 R 中将年份 + 周数转换为日期?我尝试了以下方法:

> as.POSIXct("2008 41", format="%Y %U")
[1] "2008-02-21 EST"
> as.POSIXct("2008 42", format="%Y %U")
[1] "2008-02-21 EST"

根据?strftime

%Y 年份和世纪。请注意,虽然在 原始公历,ISO 8601:2004 定义为有效 (解释为 1BC):见http://en.wikipedia.org/wiki/0_(year)。笔记 该标准还在其日历中指出 1582 年之前的年份 只能在有关各方同意的情况下使用。

%U 以十进制数表示的一年中的第几周 (00–53),使用星期日作为 一周的第一天(通常是 年作为第 1 周的第 1 天)。美国公约。

【问题讨论】:

【参考方案1】:

这有点像另一个问题you may have seen before。 :)

关键问题是:周数应该指定哪一天?是一周的第一天吗?最后?这是模棱两可的。我不知道第一周是一年中的第一天还是一年中的第七天,或者可能是一年中的第一个星期日或星期一(这是一种常见的解释)。 (而且更糟糕的是:这些通常看起来是 0 索引,而不是 1 索引。)因此,需要指定一个枚举的星期几。

例如,试试这个:

as.POSIXlt("2008 42 1", format = "%Y %U %u")

%u 指示符指定星期几。

附加说明:有关格式转换的各种选项,请参阅?strptime。重要的是要注意周的枚举,因为这些可以在年底拆分,而1 的日期是模棱两可的:它是根据星期日还是星期一指定的,还是从一年的第一天开始?这一切都应该在运行 R 代码的不同系统上进行指定和测试。我不确定 Windows 和 POSIX 系统在其中一些转换上唱相同的曲调,因此我会再次测试。

【讨论】:

不错的答案。您可能只想将 %U 的文档粘贴到 ?strptime 中,该文档精确地指定了它的行为(即第一个星期日是第 1 周的第 1 天,之前的日子属于第 0 周)。 @DWin -- 感谢您的更正。另一个提醒为什么在处理日期时再次测试和测试一个特别好的主意:) @JoshO'Brien 您在美国可能是对的,但在不同的tz 位置可能错了。在没有特定时区和非常明确的测试行为的情况下处理几周是有风险的。【参考方案2】:

POSIXlt DateTimesClasses 系统中的星期几 == 零是星期日。不完全符合圣经,也不与从“1”约定开始的 R 索引一致,但事实就是如此。零周是一年中的第一周(部分)。第一周(但第 0 周)从第一个星期日开始。 POSIXlt 中的所有其他序列类型都以 0 为起点。看看强制 POSIXlt 对象的列表元素做了什么很有趣。实际更改 POSIXlt 日期的唯一方法是更改​​ $year、$mon 或 $mday 元素。其他的似乎是副现象。

  today <- as.POSIXlt(Sys.Date())
  today  # Tuesday
#[1] "2012-02-21 UTC"
     today$wday <- 0  # attempt to make it Sunday
     today
# [1] "2012-02-21 UTC"   The attempt fails
 today$mday <- 19
 today
#[1] "2012-02-19 UTC"   Success

【讨论】:

【参考方案3】:

我自己并没有想出这个(它取自 Forester 的 blog post),但是我想我会把它添加到答案列表中,因为它是我第一次实现 ISO 8601 周数约定在 R 中见过。

毫无疑问,周数是一个非常模棱两可的话题,但我更喜欢 ISO 标准,而不是通过 format(..., "%U") 当前实施的周数,因为这似乎是大多数人都同意的,至少在德国(日历等) .).

我已将实际函数 def 放在底部,以便于首先关注输出。另外,我偶然发现了包ISOweek,也许值得一试。

方法比较

x.days  <- c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
x.names <- sapply(1:length(posix), function(x) 
    x.day <- as.POSIXlt(posix[x], tz="Europe/Berlin")$wday
    if (x.day == 0) 
        x.day <- 7
    
    out <- x.days[x.day]
)

data.frame(
    posix, 
    name=x.names,
    week.r=weeknum, 
    week.iso=ISOweek(as.character(posix), tzone="Europe/Berlin")$weeknum
)

# Result

        posix name week.r week.iso
1  2012-01-01  Sun      1  4480458
2  2012-01-02  Mon      1        1
3  2012-01-03  Tue      1        1
4  2012-01-04  Wed      1        1
5  2012-01-05  Thu      1        1
6  2012-01-06  Fri      1        1
7  2012-01-07  Sat      1        1
8  2012-01-08  Sun      2        1
9  2012-01-09  Mon      2        2
10 2012-01-10  Tue      2        2
11 2012-01-11  Wed      2        2
12 2012-01-12  Thu      2        2
13 2012-01-13  Fri      2        2
14 2012-01-14  Sat      2        2
15 2012-01-15  Sun      3        2
16 2012-01-16  Mon      3        3
17 2012-01-17  Tue      3        3
18 2012-01-18  Wed      3        3
19 2012-01-19  Thu      3        3
20 2012-01-20  Fri      3        3
21 2012-01-21  Sat      3        3
22 2012-01-22  Sun      4        3
23 2012-01-23  Mon      4        4
24 2012-01-24  Tue      4        4
25 2012-01-25  Wed      4        4
26 2012-01-26  Thu      4        4
27 2012-01-27  Fri      4        4
28 2012-01-28  Sat      4        4
29 2012-01-29  Sun      5        4
30 2012-01-30  Mon      5        5
31 2012-01-31  Tue      5        5

函数定义

它直接取自blog post,我刚刚更改了一些小东西。该功能仍然有点粗略(例如第一次约会的周数很远),但我发现这是一个不错的开始!

ISOweek <- function(
    date, 
    format="%Y-%m-%d", 
    tzone="UTC", 
    return.val="weekofyear"
)
  ##converts dates into "dayofyear" or "weekofyear", the latter providing the ISO-8601 week
  ##date should be a vector of class Date or a vector of formatted character strings
  ##format refers to the date form used if a vector of
  ##  character strings  is supplied

  ##convert date to POSIXt format 
  if(class(date)[1]%in%c("Date","character"))
    date=as.POSIXlt(date,format=format, tz=tzone)
  

#  if(class(date)[1]!="POSIXt")
  if (!inherits(date, "POSIXt")) 
    print("Date is of wrong format.")
    break
  else if(class(date)[2]=="POSIXct")
    date=as.POSIXlt(date, tz=tzone)
  
print(date)

  if(return.val=="dayofyear")
    ##add 1 because POSIXt is base zero
    return(date$yday+1)
  else if(return.val=="weekofyear")
    ##Based on the ISO8601 weekdate system,
    ## Monday is the first day of the week
    ## W01 is the week with 4 Jan in it.
    year=1900+date$year
    jan4=strptime(paste(year,1,4,sep="-"),format="%Y-%m-%d")
    wday=jan4$wday

    wday[wday==0]=7  ##convert to base 1, where Monday == 1, Sunday==7

    ##calculate the date of the first week of the year
    weekstart=jan4-(wday-1)*86400  
    weeknum=ceiling(as.numeric((difftime(date,weekstart,units="days")+0.1)/7))

    #########################################################################
    ##calculate week for days of the year occuring in the next year's week 1.
    #########################################################################
    mday=date$mday
    wday=date$wday
    wday[wday==0]=7
    year=ifelse(weeknum==53 & mday-wday>=28,year+1,year)
    weeknum=ifelse(weeknum==53 & mday-wday>=28,1,weeknum)

    ################################################################
    ##calculate week for days of the year occuring prior to week 1.
    ################################################################

    ##first calculate the numbe of weeks in the previous year
    year.shift=year-1
    jan4.shift=strptime(paste(year.shift,1,4,sep="-"),format="%Y-%m-%d")
    wday=jan4.shift$wday
    wday[wday==0]=7  ##convert to base 1, where Monday == 1, Sunday==7
    weekstart=jan4.shift-(wday-1)*86400
    weeknum.shift=ceiling(as.numeric((difftime(date,weekstart)+0.1)/7))

    ##update year and week
    year=ifelse(weeknum==0,year.shift,year)
    weeknum=ifelse(weeknum==0,weeknum.shift,weeknum)

    return(list("year"=year,"weeknum"=weeknum))
  else
    print("Unknown return.val")
    break
  

【讨论】:

以上是关于如何在 R 中解析年 + 周数?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 twitter 引导日期选择器中显示周数

SQL - 如何使用 ISO 周获得年周?

如何在 LINQ SQL C# 中返回动态周数?

怎么取两个日期之间的周数

如何获取 ISO-8601 GMT/UTC 年周数

如何使用熊猫在年份变化时继续周数