查看原文
其他

Stata日期计算:一个月有几个周

连享会 连享会 2023-10-24

👇 连享会 · 推文导航 | www.lianxh.cn


连享会课程 · 深度因果推断

作者:鞠瑶蕾 (吉林大学)
邮箱:1045751085@qq.com

温馨提示: 文中链接在微信中无法生效。请点击底部「阅读原文」。或直接长按/扫描如下二维码,直达原文:

编者按:本文主要整理自下文,特此致谢!
Source:Cox N J. Stata tip 145: Numbering weeks within months[J]. The Stata Journal, 2022, 22(1): 224-230. -PDF-


目录

  • 1. 背景介绍

  • 2. 日期的不同设定

  • 3. 最简单的周设定

  • 4. 其他的周设定

  • 5. 结语

  • 6. 参考文献

  • 7. 相关推文



1. 背景介绍

研究者们想通过一个变量来计算出每天属于哪个月的哪个周,这件事充满挑战。因为他们既需要解决周的不同含义,又要根据研究设计编辑 Stata 代码。Cox (2010,2012a,2012b,2018b,2019) 说明了一些日期和时间的注意事项。

Stata 对周的设定比较特殊:一年的第一个周从 1 月 1 日开始,第二个周从 1 月 8 日开始,以此类推,每周 7 天,12 月 31 日的时候 52 个周结束。

Stata 的基础设定中不包含第 53 个周,第 52 个周是 8 天还是 9 天取决于这一年是否为闰年。这样的设定有一个明显的优势,即周总是嵌套在年之内,不会跨年。然而,这个设定在日常生活和工作中似乎很少使用。本文介绍的 Stata 使用技巧正是基于这样一个假设:周的设定条件存在差异。

我们建立一个沙盒数据集,包含 2021 年前三个月的日期,1 月、2 月、3 月的天数分别为 31 天、28 天、31 天,前三个月一共有 90 天 (90=31+28+31)。沙盒数据集的建立过程如下:

. set obs 90
. generate ddate = mdy(12, 31, 2020) + _n
. format ddate %td
. list if inlist(_n, 1, _N)

+-----------+
| ddate |
|-----------|
1. | 01jan2021 |
1. | 31mar2021 |
+-----------+

. generate mdate = mofd(ddate)
. format mdate %tm

2. 日期的不同设定

本文先介绍一些日期的基本设定知识,以帮助读者理解后续内容。在 Stata 中,日期以整数形式保存,第一个日期是 1960 年 1 月 1 日 (数值为 0)。然后,使用 mdy() 命令获得日期。例如:

. display mdy(12, 31, 2020)
22280

若 1960 年 1 月 1 日对应的数值是 0,那么 2020 年 12 月 31 日对应的数值是 22280。display 命令只是以整数形式呈现日期 (距离 1960 年 1 月 1 日的天数),并不会改变日期的储存状态。

display 命令可以通过以下代码改变日期的呈现形式:

. display %td 22280
31dec2020

%td 是默认的日期显示格式,可以使用 format 命令将变量与呈现形式相关联。本文使用 mofd() 函数来生成 “月+日”,应用 %tm 作为默认的日期格式。ym() 函数能够将年和月组装成一个日期形式,作用类似于 mdy()monthly() 用于处理字符串,作用类似于 daily()

. display ym(2021, 1)
732

上面的两个例子说明,2021 年 1 月距离 1960 年 1 月 1 日间隔 732 个月,因此 2021 年 1 月的数值是整数 732。

这说明改变日期格式并不会改变实际日期。因此,本文强调改变日期呈现形式不是一种日期转换为另一种日期的方法。

3. 最简单的周设定

如何设定每个月的周呢?最简单的设定是第一周是第一天到第七天,第二周是第八天到第十四天,以此类推。按照这一设定,每个月通常有 5 周,最后一周是 1 天、2 天还是 3 天主要取决于这个月的天数是 29 天、30 天还是 31 天。此外,非闰年的 2 月天数是 28 天,有四个完整的周。

从 “年+月+日” 中提取 “月” 是一种常见需求,day() 能够提取 “日”,取值是 1 至 31。在此基础上,我们需要借助 ceil() 函数把天数映射到周数。

. generate wofm = ceil(day(ddate)/7)

如上述代码所示,将 day(ddate) 的数值除以 7,结果会是 1/7、2/7、3/7、4/7、5/7、6/7、7/7、8/7,以此类推,直到 31/7。ceil() 函数会向上取整数,因此 1/7 会四舍五入为 1,其他数值同理。

在日期计算中,ceil()floor() 函数经常被忽略,我们应该尽力去使用它们 (Cox,2003,2011,2018a) 。

在执行上述步骤时,可以先将 day(ddate) 的结果放入一个新变量中。然后可以根据除法四舍五入:

. generate day = day(ddate)
. generate wofm = ceil(day/7)

如果研究者们需要一个新变量单独保存日度数据,那么应该像上面这样编写代码,这样做更便于他人理解和使用,然后谨慎地检查结果。

. tabulate mdate wofm

| wofm
mdate | 1 2 3 4 5 | Total
-----------+------------------------------+-------
2021m1 | 7 7 7 7 3 | 31
2021m2 | 7 7 7 7 0 | 28
2021m3 | 7 7 7 7 3 | 31
-----------+------------------------------+-------
Total | 21 21 21 21 6 | 90

上面的结果是正常的,因为 1 月和 3 月是 31 天,包括 4 个完整的周和额外的 3 天,而 2 月只包括 4 个完整的周。进一步地,再仔细检查取值 1 至 5 是否与日历一一对应,代码是否能完全复刻闰年的日期分布情况。

4. 其他的周设定

另外一种周的设定可能包括从周日开始到周六结束或从周一开始到周日结束。不同地区对周的定义各不相同,这点应尤其注意。例如,多年来,我所在的大学有一个惯例,第一学期的教学周从周四到周三,其他学期的教学周从周一到周五,这样做的目的是安排每学年开始的入学欢迎仪式和相关活动。

接下来,本文介绍一个通用的代码使用技巧,可以涵盖所有周的设定情况。Stata 有一个函数 dow(),周日的取值为 0,周一取值为 1,以此类推,直到周六取值为 6。接下来,我们假设周日是每周的第一天。

. bysort mdate (ddate): generate WOFM = sum(dow(ddate) == 0)

为了让变量取值与周的设定相符,本文使用 bysort 命令,在每个月单独计算取值。冒号后面的代码是为了计算本月距离现在的周日次数。

dow(date) 在周日等于 0,其他日子不等于 0。当 dow(ddate)==0 时,则返回数值 1;当 dow(ddate)!=0 时,则返回数值 0。sum() 函数可以计算 1 和 0 的加总。Mata 中也有类似函数 runningsum(),在有些情况下,加总的值被称为cusums,这个术语既有优点也有缺点,通常不在 Stata 中使用。

在每个月的开头,dow(ddate)==0 的取值有 0 和 1 两种情况。在同一个月份,每周的周日都取值为 1,其他日子取值为 0。接下来,本文展示这一命令在上文创建的沙盒数据集中的效果:

. tabulate mdate WOFM

| WOFM
mdate | 0 1 2 3 4 5 |Total
-----------+------------------------------------+-----
2021m1 | 2 7 7 7 7 1 | 31
2021m2 | 6 7 7 7 1 0 | 28
2021m3 | 6 7 7 7 4 0 | 31
-----------+------------------------------------+-----
Total | 14 21 21 21 12 1 | 90

将上述结果与 2021 年前三个月对比发现,每个月的第一个星期天分别是 1 月 3 日、2 月 7 日和 3 月 7 日。相应地,每个月都以一个不完整的周 (非周日) 开始,因此每个月的开头的取值均为 0。以此类推发现,2021 年 8 月是从周日开始的,因此 8 月的第一天取值为 1。

这是一个通用的编码。如果一个周从周一开始周日结束,那么可以通过改变 dow() 的取值实现,即 dow(ddate) 是否等于1。如果希望周的取值从 1 开始,可以在计算 wofm 时加 1。

. by mdate: replace WOFM = WOFM + 1 if WOFM[1] == 0

5. 结语

考虑到不同国家和学科领域对日历的设定不同,周的设定可能存在其他的情况。本文在这里只是提供一个通用的技巧,帮助有需要的研究者实现研究设计。

日期数据是复杂的:实际生活中存在着各式各样的日期规则,但是 Stata 在日期处理方面仍然面临一系列新的挑战,其他软件通过一个或多个不同的数据或变量类型来处理日期。Stata 以整数形式简化了日期的呈现,但仍然需要研究者充分掌握格式和函数的细节,在这方面,help datetime可能是一个好的开始。

函数很重要:精确处理日期数据的关键是要了解 Stata 的函数,这里不仅包括日期函数 (如 day()dow()) ,还包括其他通用函数 (如 sum()ceil())。

沙盒数据集很有用:部分研究者经常将大型而复杂的数据集读入内存,却缺少具体的处理代码。此时,可以备份或创建一个小型的沙盒数据集 (sandbox dataset) ,就像上文中设计的那样,可以快速得到结果并与正确答案比较。此外,可以使用 display 去呈现单个值或将Mata作为数据美化器。

6. 参考文献

  • Cox, N. J. (2002). Speaking stata: How to move step by: Step. Stata Journal, 2(1), 86-102. -PDF-
  • Cox, N. J. (2003). Stata tip 2: Building with floors and ceilings. Stata Journal, 3(4), 446-447. -PDF-
  • Cox, N. J. (2010). Stata tip 68: Week assumptions. Stata Journal, 10(4), 682-685. -PDF-
  • Cox, N. J. (2011). Speaking stata: Fun and fluency with functions. Stata Journal, 11(3), 460-471. -PDF-
  • Cox, N. J. (2012a). Stata tip 111: More on working with weeks. Stata Journal, 12(3), 565-569. -PDF-
  • Cox, N. J. (2012b). Stata tip 111: More on working with weeks, erratum. Stata Journal, 12(4), 765-765. -PDF-
  • Cox, N. J. (2012c). Stata tip 113: Changing a variable's format: What it does and does not mean. Stata Journal, 12(4), 761-764. -PDF-
  • Cox, N. J. (2018a). Speaking stata: From rounding to binning. Stata Journal, 18(3), 741-754. -PDF-
  • Cox, N. J. (2018b). Stata tip 130: 106610 and all that: Date variables that need to be fixed. Stata Journal, 18(3), 755-757. -PDF-
  • Cox, N. J. (2019). Speaking stata: The last day of the month. Stata Journal, 19(3), 719-728. -PDF-
  • Henkin, D. M. 2021. The Week: A History of the Unnatural Rhythms That Made Us Who We Are. New Haven, CT: Yale University Press.
  • Reingold, N. M., and N. Dershowitz. 2018. Calendrical Calculations: The Ultimate Edition. Cambridge: Cambridge University Press.

7. 相关推文

Note:产生如下推文列表的 Stata 命令为:
lianxh 日期 时间, m
安装最新版 lianxh 命令:
ssc install lianxh, replace

  • 专题:Stata入门
    • Stata:根据当前日期返回是周几
  • 专题:Stata命令
    • Stata:允许时间效应序列相关的面板二维聚类标准误-xtregtwo
  • 专题:数据处理
    • Stata:时间序列数据转换-tstransform
    • Stata 日期格式转换
    • Stata:如何保留时间连续的样本
    • Stata:文字型日期格式的转换
    • Stata数据处理:字符型日期变量的转换
    • 如何处理时间序列中的日期间隔-(with-gaps)-问题?
  • 专题:回归分析
    • Stata:时间虚拟变量还是时间趋势项?
    • 傻傻分不清:时间趋势项与时间虚拟变量


课程推荐:机制分析与政策优化(2023年8月22-24日)
主讲老师:杨海生
课程地点:西安·西北工业大学
🍓 课程主页https://www.lianxh.cn/news/72ab78cb6b39f.html

New! Stata 搜索神器:lianxhsongbl  GIF 动图介绍
搜: 推文、数据分享、期刊论文、重现代码 ……
👉 安装:
. ssc install lianxh
. ssc install songbl
👉  使用:
. lianxh DID 倍分法
. songbl all

🍏 关于我们

  • 连享会 ( www.lianxh.cn,推文列表) 由中山大学连玉君老师团队创办,定期分享实证分析经验。
  • 直通车: 👉【百度一下: 连享会】即可直达连享会主页。亦可进一步添加 「知乎」,「b 站」,「面板数据」,「公开课」 等关键词细化搜索。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存