Generating a composite date variable - stata

I want to generate a variable month that has the month and year together as 2013M01.
Below is a sample of my data:
clear
input expected_arrival_month year
1 2013
2 2014
3 2015
4 2016
5 2017
6 2018
end
I tried the following command:
generate month = .
replace month = 2013M01 if expected_arrival_month == 1 & year == 2013
However, I received the error:
2013M01 invalid name
r(198)
How can I get the desired output?

For essentially all Stata purposes a numeric monthly date variable is better than anything hand- or homemade (and certainly than dates held as string variables). You can get such variables to appear as you ask. You certainly do not need to calculate individual values directly. Although this code is for a minimal dataset it will apply to all values in numeric variables as you describe. See help datetime for invaluable (and unavoidable) information.
clear
set obs 1
generate year = 2013
generate arrival_month = 1
generate wanted = ym(year, arrival_month)
format wanted %tmCCYY!MNN
list
+---------------------------+
| year arriva~h wanted |
|---------------------------|
1. | 2013 1 2013M01 |
+---------------------------+
(As commented, you should provide example data directly and in a way that makes variable types clear. If one or both variables are really string, apply destring first or use monthly().)

The issue here is in dealing with string rather than numeric variables. Given that the variable you are generating is a string variable, the contents of the variable must be enclosed in quotation marks:
generate month = "2013M01" if expected_arrival_month == 1 & year == 2013
There would also be other more efficient ways to deal with this generation, for example using Stata's egen command (and concat), or datetime functions as indicated in another response.

Related

Stata: How to modify some values in a string variable but keep original values?

I am working with a very large dataset (1 million obs.).
I have a string date that looks like this
key seq startdate (string)
AD07 1 August 2011
AD07 2 June 2011
AD07 3 February 2004
AD07 4 November 2004
AD07 5 2001
AD07 6 January 1998
AD5c23 1 January 2014
AD5c235 2 February 2014
AD5c235 3 2014
These are self-reported employment dates.
Some did not report the month at which they started.
But I would like to replace for AD07 the date “2001” to “January 2001”. Hence I cannot simply replace it because I would like to keep the original years but add the month in the string variable.
I started with:
levelsof start if start<="2016", local(levels)
which gives me all the years without the month from 1900 to 2016.
Now I would like to add "January" for the years without the month and keep original years.
How should I do that without using replace for every year? foreach loop?
You have a serious data quality problem if people are claiming to have started work in 1900 and every year since then! Even considering early employment starts and delayed retirement, that implies people older than the oldest established age.
Also, imputing "January" will impart bias as almost all job durations will be longer than they would have been. Real January starts will be correct, but no others: "June" or "July" or random months would make more obvious statistical sense.
That said, there is no loop needed here. You're asking for one line, say
replace startdate = "January " + startdate if length(trim(date)) == 4
or
replace startdate = "January " + startdate if real(startdate) < .
-- assuming a follow-up in converting to numeric dates. The logic there is that all year-only dates trim down to 4 characters, or (better) that feeding month names to real() will yield missings.
That said in turn, creating a new variable is better practice than over-writing one. Also, consider throwing away the month detail. Is it needed?
EDIT
You may have another problem if there are people with two or more jobs in the same year without month specifications. You don't want to impute all months in question as "January". You can check for such observations by
gen byte incomplete = real(startdate) < .
gen year = substr(trim(startdate), -4, 4)
bysort key year incomplete : gen byte multiplebad = incomplete & _N > 1

Difference between dropping years and "if Year > 2005"

I have a dataset of the top management teams of US banks from 2005 - 2015.
Now I want to generate a change-variable if a TMT composition changed between 2006 and 2009.
So first I used:
drop if Year > 2009
drop if Year < 2006
by id (id), sort: gen changed = (DirectorID[1] != DirectorID[_N])
and afterwards I used
by id (id), sort: gen changed = (DirectorID[1] != DirectorID[_N]) if Year < 2010 & Year > 2005
However there is a difference in output between two variables:
247 cases of "No change" and 853 cases of "Change" in the first and 116 cases of "No change" and the rest as "Changed" in the second variable
Could anyone clarify what the differences between these two commands are in Stata?
There are a couple reasons you may be seeing a different count of changes to the dataset. The data is most likely sorted differently for these two calls. The (id) parts have no effect here because you are already sorting by id. What you likely want to do is residually sort by year. So, bysort id (Year) - this way the dataset will be in the same order for each command you type. In the second command, the if clause is going to set the variable changed to missing for observations outside of the year range, but those observations are still being included in the calculation. You could create a new variable to flag the years of interest, and then add that new variable to the bysort call.
Lastly, you need to decide whether you only want to look at changes year-over-year (the value of the changed could vary by year within id), or have the value of changed reflect whether there were any changes in DirectorID over the entire time frame of interest (the value of changed would be constant within id).
Here's a toy example illustrating the difference. Essentially, when you drop the data, the last and the first observation could be the same, but in general you will have less data to compare the first and last observation since much of the data will be gone. When you use if, then the data is still there, even though the calculation is restricted to the middle observation by the if:
. clear
. input id year director_id
id year directo~d
1. 1 2016 10
2. 1 2017 20
3. 1 2018 30
4. end
.
. bys id (year): gen changed = (director_id[1] != director_id[_N]) if year < 2018 & year > 2016
(2 missing values generated)
. list, clean noobs
id year direct~d changed
1 2016 10 .
1 2017 20 1
1 2018 30 .
.
. drop if inlist(year, 2016,2018)
(2 observations deleted)
. bys id (year): gen changed2 = (director_id[1] != director_id[_N]) if year < 2018 & year > 2016
. list, clean noobs
id year direct~d changed changed2
1 2017 20 1 0
I added a sort by year since that seems in the spirit of your exercise.

How to destring a date in Stata containing just the year?

I have a string variable in Stata called YEAR with format "aaaa" (e.g. 2011). I want to replace "aaaa" with "31decaaaa" and destring the obtained variable.
My feeling is that the best way to proceed could be firstly destringing the variable YEAR and then adding "31dec". To destring the variable YEAR I have tried the command date but it does not seem to work. Any suggestion?
It would be best to describe your eventual goal here, as use of destring just appears to be what you have in mind as the next step.
If your goal is, given a string variable year, to produce a daily date variable for 31 December in each year, then destring is not necessary. Here are three ways to do it:
gen date = daily("31 Dec" + year, "DMY")
gen date = date("31 Dec" + year, "DMY")
gen date = mdy(12, 31, real(year))
Incidentally, there is no likely gain for Stata use in daily dates 365 or 366 days apart, as they just create a time series that is mostly implicit gaps.
If your data are yearly, but just associated with the end of each calendar year, keep them as yearly and use a display format to show "31 Dec", or the equivalent, in output.
. di %ty!3!1_!D!e!c_CCYY 2015
31 Dec 2015
Detail. date() is a function, not a command, in Stata. We can't comment on "does not seem to work" as no details are given of what you tried or what happened. daily() is just a synonym for date().

Convert two numeric into a date format

I have two numeric variables, year and month. year variable has data such as 2010 and month variable has data such as 1 and 10 (1 through 9 doesn't have zero at the front). I need to combine these two variables and then convert it to YYMMn6. format so that I can merge another dataset based on the date.
For example, the input is:
2012 1
2012 10
The output I want is (in YYMMn6. format):
201201
201210
The codes I tried so far:
year1=close_year;
year2=clse_month;
yearmonth = cats(of year1-year2); *this results in character variable;
DATE2 = INPUT(PUT(yearmonth,8.),YYMMN6.);
FORMAT DATE2 YYMMN6.;
Of course I get an error message. Thanks.
With numeric variables I'd use MDY function rather than putting and whatnot; you're having trouble here because 20101 isn't a valid YYMM value.
dateval = mdy(monthval,1,yearval);
format dateval yymmn6.;
Note that the 'final' date format is wholly unrelated to whatever you use to input the date variable from an informat; there's no difference from SAS's point of view between
dateval = input('01JAN2010',DATE9.);
format dateval YYMMN6.;
and
dateval = input('201001',YYMMN6.);
format dateval YYMMN6.;
The input/informat is converting a value into a numeric number of days since 1/1/1960. The final format is telling SAS how to display that newly created number.
You can use the answer mentioned by Joe which
would give you the flexibility to change to a different format if you want later on,
without any hassle.
would keep the variables in numeric format, so mathematical or
date functions would be easy to apply.
or you can use
mydate=put(mdy(monthval,1,yearval),yymmn6.);
if you want the output in char format.
Both are correct. Choose as per your requiremnt.

Stata keeping even years

If I have data for every year of 1932 to 2012, how do I keep only the even number years from 1946 to 2012 in Stata? I've tried the following:
keep if year == 1946(2)2012
But it doesn't seem to help.
The error you receive with your code is: unknown function 1946(). Stata thinks 1946 is a function because it is followed by an opening parenthesis. It is expecting an expression and functions can be part of an expression. However, you are giving it a numlist (help numlist), and that is not allowed.
An example that works:
clear
set more off
*----- example data -----
set obs 81
egen year = seq(), from(1932) to(2012)
list
*----- what you want -----
keep if mod(year,2) == 0 & year >= 1946
list
Note I used a (legal) function, namely, the modulo function.