Reputation: 754
Stata does not seem to have a bimonthly (twice a month) time standard. I have time series at this rather uncommon frequency. I was wondering what would be the best way to circumvent this in Stata. Does anybody have a suggestion? Would creating an artificial time index be the easiest way to go?
Upvotes: 0
Views: 632
Reputation: 37208
This answer hinges entirely on a late comment by the OP that
I have a regularity, but it's of the sort every 3rd and 19th day of month
Let's take that literally. The spirit of such dates is that they are approximately equally spaced, and useful as such, but for many time series problems, we will want to pretend that they are exactly equally spaced. No existing date type in Stata corresponds, but it is easy to create one.
The first block of code just creates a sandbox example dataset, given that the OP did not provide one.
clear
set obs 48
egen m = seq(), from(1) to(12) block(2)
egen y = seq(), from(2015) to(2016) block(24)
gen dailydate = mdy(m, cond(mod(_n, 2), 3, 19), y)
format dailydate %td
list
+-----------------------+
| m y dailydate |
|-----------------------|
1. | 1 2015 03jan2015 |
2. | 1 2015 19jan2015 |
3. | 2 2015 03feb2015 |
4. | 2 2015 19feb2015 |
5. | 3 2015 03mar2015 |
|-----------------------|
6. | 3 2015 19mar2015 |
7. | 4 2015 03apr2015 |
8. | 4 2015 19apr2015 |
9. | 5 2015 03may2015 |
10. | 5 2015 19may2015 |
|-----------------------|
11. | 6 2015 03jun2015 |
12. | 6 2015 19jun2015 |
13. | 7 2015 03jul2015 |
14. | 7 2015 19jul2015 |
15. | 8 2015 03aug2015 |
|-----------------------|
16. | 8 2015 19aug2015 |
17. | 9 2015 03sep2015 |
18. | 9 2015 19sep2015 |
19. | 10 2015 03oct2015 |
20. | 10 2015 19oct2015 |
|-----------------------|
21. | 11 2015 03nov2015 |
22. | 11 2015 19nov2015 |
23. | 12 2015 03dec2015 |
24. | 12 2015 19dec2015 |
25. | 1 2016 03jan2016 |
|-----------------------|
26. | 1 2016 19jan2016 |
27. | 2 2016 03feb2016 |
28. | 2 2016 19feb2016 |
29. | 3 2016 03mar2016 |
30. | 3 2016 19mar2016 |
|-----------------------|
31. | 4 2016 03apr2016 |
32. | 4 2016 19apr2016 |
33. | 5 2016 03may2016 |
34. | 5 2016 19may2016 |
35. | 6 2016 03jun2016 |
|-----------------------|
36. | 6 2016 19jun2016 |
37. | 7 2016 03jul2016 |
38. | 7 2016 19jul2016 |
39. | 8 2016 03aug2016 |
40. | 8 2016 19aug2016 |
|-----------------------|
41. | 9 2016 03sep2016 |
42. | 9 2016 19sep2016 |
43. | 10 2016 03oct2016 |
44. | 10 2016 19oct2016 |
45. | 11 2016 03nov2016 |
|-----------------------|
46. | 11 2016 19nov2016 |
47. | 12 2016 03dec2016 |
48. | 12 2016 19dec2016 |
+-----------------------+
Code here is based on the assumption that there should be precisely 24 values in each year. However, the code allows for the possibility that dates are repeated because the data are panel data; and it allows gaps to exist whereby some dates are not present in the dataset.
We first extract month, day and year components of the daily dates. These variables may already exist (one of many details the OP is not making clear).
gen month = month(dailydate)
gen year = year(dailydate)
gen day = day(dailydate)
assert inlist(day, 3, 19)
Then a bimonthly date in the spirit of Stata's dates has origin at the start of 1960. This detail is not important, but it is not difficult either. Users can't specify new display formats, but what we can do is assign value labels to the new dates which correspond to display formats of the original daily dates. Here labmask
must be installed before it can be used: search labmask
gives download locations.
gen newdate = 24 * (year - 1960) + 2 * (month - 1) + (day == 19)
list, sepby(year month)
+------------------------------------------------------+
| m y dailydate month year day newdate |
|------------------------------------------------------|
1. | 1 2015 03jan2015 1 2015 3 1320 |
2. | 1 2015 19jan2015 1 2015 19 1321 |
|------------------------------------------------------|
3. | 2 2015 03feb2015 2 2015 3 1322 |
4. | 2 2015 19feb2015 2 2015 19 1323 |
|------------------------------------------------------|
5. | 3 2015 03mar2015 3 2015 3 1324 |
6. | 3 2015 19mar2015 3 2015 19 1325 |
|------------------------------------------------------|
7. | 4 2015 03apr2015 4 2015 3 1326 |
8. | 4 2015 19apr2015 4 2015 19 1327 |
|------------------------------------------------------|
9. | 5 2015 03may2015 5 2015 3 1328 |
10. | 5 2015 19may2015 5 2015 19 1329 |
|------------------------------------------------------|
11. | 6 2015 03jun2015 6 2015 3 1330 |
12. | 6 2015 19jun2015 6 2015 19 1331 |
|------------------------------------------------------|
13. | 7 2015 03jul2015 7 2015 3 1332 |
14. | 7 2015 19jul2015 7 2015 19 1333 |
|------------------------------------------------------|
15. | 8 2015 03aug2015 8 2015 3 1334 |
16. | 8 2015 19aug2015 8 2015 19 1335 |
|------------------------------------------------------|
17. | 9 2015 03sep2015 9 2015 3 1336 |
18. | 9 2015 19sep2015 9 2015 19 1337 |
|------------------------------------------------------|
19. | 10 2015 03oct2015 10 2015 3 1338 |
20. | 10 2015 19oct2015 10 2015 19 1339 |
|------------------------------------------------------|
21. | 11 2015 03nov2015 11 2015 3 1340 |
22. | 11 2015 19nov2015 11 2015 19 1341 |
|------------------------------------------------------|
23. | 12 2015 03dec2015 12 2015 3 1342 |
24. | 12 2015 19dec2015 12 2015 19 1343 |
|------------------------------------------------------|
25. | 1 2016 03jan2016 1 2016 3 1344 |
26. | 1 2016 19jan2016 1 2016 19 1345 |
|------------------------------------------------------|
27. | 2 2016 03feb2016 2 2016 3 1346 |
28. | 2 2016 19feb2016 2 2016 19 1347 |
|------------------------------------------------------|
29. | 3 2016 03mar2016 3 2016 3 1348 |
30. | 3 2016 19mar2016 3 2016 19 1349 |
|------------------------------------------------------|
31. | 4 2016 03apr2016 4 2016 3 1350 |
32. | 4 2016 19apr2016 4 2016 19 1351 |
|------------------------------------------------------|
33. | 5 2016 03may2016 5 2016 3 1352 |
34. | 5 2016 19may2016 5 2016 19 1353 |
|------------------------------------------------------|
35. | 6 2016 03jun2016 6 2016 3 1354 |
36. | 6 2016 19jun2016 6 2016 19 1355 |
|------------------------------------------------------|
37. | 7 2016 03jul2016 7 2016 3 1356 |
38. | 7 2016 19jul2016 7 2016 19 1357 |
|------------------------------------------------------|
39. | 8 2016 03aug2016 8 2016 3 1358 |
40. | 8 2016 19aug2016 8 2016 19 1359 |
|------------------------------------------------------|
41. | 9 2016 03sep2016 9 2016 3 1360 |
42. | 9 2016 19sep2016 9 2016 19 1361 |
|------------------------------------------------------|
43. | 10 2016 03oct2016 10 2016 3 1362 |
44. | 10 2016 19oct2016 10 2016 19 1363 |
|------------------------------------------------------|
45. | 11 2016 03nov2016 11 2016 3 1364 |
46. | 11 2016 19nov2016 11 2016 19 1365 |
|------------------------------------------------------|
47. | 12 2016 03dec2016 12 2016 3 1366 |
48. | 12 2016 19dec2016 12 2016 19 1367 |
+------------------------------------------------------+
gen sdate = string(dailydate, "%tdd_m_CY")
labmask newdate, values(sdate)
The result of that last block is not shown here, but the resulting value labels are like 3 Jan 2015
: you can assign any other date display format you like.
Upvotes: 1
Reputation: 9460
In my experience, bimonthly is not always well defined.
If the gap is always regular, say every other Friday (dow=5), you can use the delta()
option like this:
clear
set obs 1488
gen date = (_n-1)*14
tsset date, delta(14)
gen lag_of_date = L1.date
gen two_lags_of_date = L2.date
format *date %td
gen dow=dow(date)
list in -10/L, clean noobs
This is yields:
. list in -11/L, clean noobs
date lag_of_~e two_lag~e dow
12aug2016 29jul2016 15jul2016 5
26aug2016 12aug2016 29jul2016 5
09sep2016 26aug2016 12aug2016 5
23sep2016 09sep2016 26aug2016 5
07oct2016 23sep2016 09sep2016 5
21oct2016 07oct2016 23sep2016 5
04nov2016 21oct2016 07oct2016 5
18nov2016 04nov2016 21oct2016 5
02dec2016 18nov2016 04nov2016 5
16dec2016 02dec2016 18nov2016 5
30dec2016 16dec2016 02dec2016 5
As you can see, the lag operators all work as expected and give you the Friday's date from two and four weeks prior, and not the previous Thursday and Wednesday or missings.
If the pattern is not regular because of holidays or whatnot, then take a look at the business calendar
functionality. Using your constraint from the comments, that would look something like this:
set more off
/* (1) Make a business calendar file */
/* (1a) Make a header with date range and the date that zero corresponds to (MODIFY THIS!) */
capture file close bc
file open bc using my_biz_cal.stbcal, write replace
file write bc "version 14.1" _n
file write bc `"purpose "3rd and 19th of every month""' _n
file write bc "range 03jan2000 19dec2025" _n
file write bc "centerdate 03jan2016" _n
/* (1b) Drop all the non-3rd and non-19th dates based on folk wisdom with a loop:
Thirty days has September,
April, June, and November.
All the rest have thirty-one,
Except for February alone,
Which hath but twenty-eight days clear,
And twenty-nine in each leap year.
*/
foreach mon in `=lower("`c(Mons)'")' {
if inlist("`mon'","sep","apr","jun","nov")==1 {
foreach d in 1 2 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 20 21 22 23 24 25 26 27 28 29 30 {
file write bc "omit date `d'`mon'*" _n
}
}
else if inlist("`mon'","feb")==1 {
foreach d in 1 2 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 20 21 22 23 24 25 26 27 28 29 {
file write bc "omit date `d'`mon'*" _n
}
}
else {
foreach d in 1 2 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 20 21 22 23 24 25 26 27 28 29 30 31 {
file write bc "omit date `d'`mon'*" _n
}
}
}
file close bc
/* (2) Try Using The Business Calendar */
clear
bcal load my_biz_cal
set obs 100
gen my_date = _n-50
format my_date %tbmy_biz_cal
tsset my_date
gen lag_of_date = L1.my_date
gen two_lags_of_date = L2.my_date
format *date %tbmy_biz_cal
list in 1/10, clean noobs
di %tbmy_biz_cal -1
di %tbmy_biz_cal 0
di %tbmy_biz_cal 1
Upvotes: 1
Reputation: 19375
yes that's the only solution
create your time index and then
tsset my_time_index
Upvotes: 0