<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>The Stata Things &#187; date and time functions</title>
	<atom:link href="http://enoriver.net/index.php/tag/date-and-time-functions/feed/" rel="self" type="application/rss+xml" />
	<link>http://enoriver.net</link>
	<description>computing for fun and profit</description>
	<lastBuildDate>Fri, 13 Aug 2010 20:42:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Fun with display and macros</title>
		<link>http://enoriver.net/index.php/2008/12/12/fun-with-display-and-macros/</link>
		<comments>http://enoriver.net/index.php/2008/12/12/fun-with-display-and-macros/#comments</comments>
		<pubDate>Fri, 12 Dec 2008 20:14:53 +0000</pubDate>
		<dc:creator>Gabi Huiber</dc:creator>
				<category><![CDATA[Stata]]></category>
		<category><![CDATA[date and time functions]]></category>
		<category><![CDATA[macros]]></category>

		<guid isPermaLink="false">http://enoriver.net/?p=387</guid>
		<description><![CDATA[Turns out anything you can display -- or di -- on the screen, you can also send to a macro to use later. How useful is that? Well, sometimes you need to say the same thing in different ways. The macro may be set to capture either the form or the substance, depending on which [...]]]></description>
			<content:encoded><![CDATA[<p>Turns out anything you can <code>display</code> -- or <code>di</code> -- on the screen, you can also send to a macro to use later. How useful is that? Well, sometimes you need to say the same thing in different ways. The macro may be set to capture either the form or the substance, depending on which one you need.</p>
<p>I don't usually use macros that way (OK, I wasn't even aware of the possibility until today) but today that need arose, so here's what I learned.</p>
<p>One example of the difference between a thing's looks and substance would be this:<br />
<code><br />
di c(current_date)<br />
</code><br />
What you see on the screen -- today that would be the string "12 Dec 2008" -- is different from what's behind it -- the value 17878, <em>i.e.</em>, the number of days since January 1, 1960.</p>
<p>So you could simply do<br />
<code><br />
local mydate c(current_date)<br />
di "`mydate'"<br />
</code><br />
This looks useful, and maybe it is. The local macro `mydate' above has stored the look of c(current_date), but it knows nothing about its content. You could change that if you defined that macro like this:<br />
<code><br />
local mydate=date(c(current_date),"DMY")<br />
di `mydate'<br />
</code><br />
So `mydate' is now a number, not a string. Specifically, it's an actual date -- from which you can derive things like <code>week(`mydate')</code> or <code>dow(`mydate')</code> or what have you.</p>
<p>But a look of this content, as opposed to the content itself, might be exactly what you want. For example, you may want the YYYYMMDD equivalent of today's date. Easy:<br />
<code><br />
local mydate: di %tdCYND date(c(current_date),"DMY")<br />
di `mydate'</code></p>
<p>So much about that. It's Friday, can't work too hard.</p>
]]></content:encoded>
			<wfw:commentRss>http://enoriver.net/index.php/2008/12/12/fun-with-display-and-macros/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Masks</title>
		<link>http://enoriver.net/index.php/2008/12/04/masks/</link>
		<comments>http://enoriver.net/index.php/2008/12/04/masks/#comments</comments>
		<pubDate>Thu, 04 Dec 2008 21:17:26 +0000</pubDate>
		<dc:creator>Gabi Huiber</dc:creator>
				<category><![CDATA[Stata]]></category>
		<category><![CDATA[date and time functions]]></category>
		<category><![CDATA[mask]]></category>

		<guid isPermaLink="false">http://enoriver.net/?p=353</guid>
		<description><![CDATA[One way to get free Stata help is to post your question to the Statalist. A dedicated band of Stata users will go at it like a school of hungry piranhas at a drowning zebu, and odds are excellent that whatever baffled you will be ripped apart practically while you watch. Another is to just [...]]]></description>
			<content:encoded><![CDATA[<p>One way to get free Stata help is to post your question to the <a title="Stata listserver" href="http://www.stata.com/statalist/">Statalist</a>. A dedicated band of Stata users will go at it like a school of hungry piranhas at a drowning zebu, and odds are excellent that whatever baffled you will be ripped apart practically while you watch. Another is to just blog about your work.</p>
<p>A while ago I posted about keeping track of files I receive every week, with names such as client_YYYYMMDD.txt. I don't receive them on the same day, and I get a lot of them from several clients. It'd be nice to be able to make Stata look for them without me having to spell out the date of arrival. Well, there is a way. The YYYYMMDD variation poses no more of a challenge than any other way of describing a date -- <em>e.g.</em> December 4, 2008 -- once you get acquainted with the <code>mask</code> feature of Stata's clock and date functions. Take this code for example:<br />
<code><br />
local clients "foo bar"<br />
local start=date("1nov2008","dmy")<br />
local end=date(c(current_date),"dmy")<br />
</code><code><br />
foreach client in `clients' {<br />
   forvalues i=`start'/`end' {<br />
</code><code><br />
      local x=string(`i',"%tdCYND") // one way to YYYYMMDD<br />
      local x: display %tdCYND `i'  // and here's another<br />
</code><code><br />
      capture confirm file "`file_path'`client'_`x'.txt"<br />
      if _rc==0 {<br />
         di "Success. Got a file from `client' on `i'."<br />
         // your code goes here<br />
      }<br />
   }<br />
}</code></p>
<p>This is a beautiful solution. Steli's comment in response to <a href="http://enoriver.net/index.php/2008/11/11/leading-zeroes/">my post on leading zeroes</a> had sent me riffling through the friendly manual (Data Management volume, dates and times section; page 76 if your manual is for Stata 10). That enlightened me on how the masks on Stata's time and clock functions work. The time to deploy that grain of wisdom arrived a few minutes ago. </p>
<p>One last thing: you may have noticed that this example is written in Stata 9. In Stata 10 the %td mask would be a little different, and the "dmy" part of the date function would be "DMY".</p>
]]></content:encoded>
			<wfw:commentRss>http://enoriver.net/index.php/2008/12/04/masks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Leading zeroes</title>
		<link>http://enoriver.net/index.php/2008/11/11/leading-zeroes/</link>
		<comments>http://enoriver.net/index.php/2008/11/11/leading-zeroes/#comments</comments>
		<pubDate>Tue, 11 Nov 2008 20:23:56 +0000</pubDate>
		<dc:creator>Gabi Huiber</dc:creator>
				<category><![CDATA[Stata]]></category>
		<category><![CDATA[date and time functions]]></category>
		<category><![CDATA[leading zeroes]]></category>

		<guid isPermaLink="false">http://enoriver.net/?p=287</guid>
		<description><![CDATA[I am working on a project where occasionally I need to keep time using dates in the format YYYYMMDD. I sometimes also need to move back and forth between these dates and numeric year, month, day, which requires things like turning the numeric month 1 into the string "01". The general syntax for turning numbers [...]]]></description>
			<content:encoded><![CDATA[<p>I am working on a project where occasionally I need to keep time using dates in the format YYYYMMDD. I sometimes also need to move back and forth between these dates and numeric year, month, day, which requires things like turning the numeric month 1 into the string "01".</p>
<p>The general syntax for turning numbers to strings with leading zeroes is easy enough. Here's an example with social security numbers:</p>
<p><code>gen str9 ssn_string=string(ssn_numeric, "%09.0f")</code></p>
<p>For dates, this syntax would translate like so:</p>
<p><code><br />
local when `c(current_date)'<br />
display "`when'"<br />
</code><code><br />
local pieces "year month day"<br />
local length "4 2 2"<br />
forvalues i=1/3 {<br />
local w: word `i' of `pieces'<br />
local k: word `i' of `length'<br />
local `w'=string(`w'(date("`when'","DMY")),"%0`k'.0f")<br />
}<br />
local when="`year'`month'`day'"<br />
display "`when'"<br />
</code></p>
<p>Of course, you don't need to use the string type. Getting back to Stata's original social security number example, if you want leading zeroes but you also want to keep the numeric type, you can simply say</p>
<p><code>format ssn %09.0f</code></p>
<p>See the Stata help for <code>format</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://enoriver.net/index.php/2008/11/11/leading-zeroes/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Cheap Iceland</title>
		<link>http://enoriver.net/index.php/2008/10/25/cheap-iceland/</link>
		<comments>http://enoriver.net/index.php/2008/10/25/cheap-iceland/#comments</comments>
		<pubDate>Sat, 25 Oct 2008 22:22:31 +0000</pubDate>
		<dc:creator>Gabi Huiber</dc:creator>
				<category><![CDATA[Stata]]></category>
		<category><![CDATA[date and time functions]]></category>
		<category><![CDATA[trip planner]]></category>

		<guid isPermaLink="false">http://enoriver.net/?p=226</guid>
		<description><![CDATA[I really wish it weren't so, because good people there are hurting badly, but all of a sudden, thanks to the global credit crunch, Iceland has become a cheap destination. Icelandair will fly you to Reykjavik from Boston or New York and put you up in the Hilton for three nights. Total cost: $559+ $90 [...]]]></description>
			<content:encoded><![CDATA[<p>I really wish it weren't so, because good people there are hurting badly, but all of a sudden, thanks to the global credit crunch, Iceland has become a cheap destination. Icelandair will fly you to Reykjavik from Boston or New York and put you up in the Hilton for three nights. Total cost: $559+ $90 in various airport taxes. If you want an extra night, it's $69. </p>
<p>Given what that wonderful country has to offer, and what the right price for that is, this is an incredibly good deal, so I got busy. Kirstin and I could fly there between December 10 and 14. Got to find flights from Raleigh-Durham to either Boston or NYC, at the right times. That means toggling between Expedia.com and Icelandair.com, ballpen in hand, building and scratching out various itineraries.</p>
<p>All that recomputing of total costs, layovers, etc. with different flight combinations is not much fun. And I like seeing my data in some compact and logical form: like outbound flights arranged A to B to C, and inbound flights C to B to A. I like my layovers spelled out so I can quickly see if they're acceptable,  and I like to see the total cost of the whole thing. Finally, I don't want this information scattered across several pages.</p>
<p>This presented an opportunity for yet another frivolous use of Stata:</p>
<p><code> <br />
capture prog drop printItinerary<br />
prog def printItinerary<br />
</code><code><br />
// user input<br />
// ##########<br />
</code><code><br />
// enter the number of travelers<br />
local people      2<br />
</code><code><br />
// airport lists<br />
//   you may enter either airport codes or city names, but if you choose<br />
//   the latter, enter them as one word (e.g. NewYork). if the return trip<br />
//   is along the same airport string, enter "same". either airport list<br />
//   can be empty or missing, in case you want to plan a one-way trip.<br />
</code><code><br />
local airports_there "RDU JFK KEF"<br />
local airports_back  "same"<br />
</code><code><br />
// flight itinerary<br />
//   enter dates in the format DDmonYYYY<br />
//   enter legs of the trip as strings of 4, 6 or 8 words.<br />
//   4 words: airline, flight#, dep_hh:mm.am/pm, arr_hh:mm.am/pm<br />
//   6 words if either the departure or arrival are on next day.<br />
//   8 words if both are. (i.e., "next day" x 2 = 4 words)<br />
</code><code><br />
local date_there  "10dec2008" // as of departure, not arrival<br />
local date_back   "14dec2008" // ditto.<br />
</code><code><br />
local leg1_there "Delta 6742 4:00pm 6:00pm"<br />
local leg2_there "Icelandair 614 8:00pm 6:45am next day"<br />
</code><code><br />
local leg2_back "Icelandair 615 5:05pm 6:10pm"<br />
local leg1_back "Delta 6227 7:10pm 9:30pm"<br />
</code><code><br />
// prices<br />
//   enter numbers in the order of legs counted<br />
//   from destination. on the way back, enter<br />
//   zero for legs priced as round-trip.<br />
//   for any airport taxes, etc. not<br />
//   included in the prices by leg, enter<br />
//   the total amount per traveler.<br />
</code><code><br />
local prices_there "199 559"<br />
local prices_back  "199 0"<br />
local otherfees     90<br />
</code><code><br />
// you're done. now watch.<br />
</code><code><br />
// calculations<br />
// ############<br />
</code><code><br />
// set some constants based on layout of input strings<br />
local airln    1 // airline is always 1st word<br />
local flightno 2 // flight # is always 2nd word<br />
local deptime  3 // departure time is always 3rd word<br />
local ways     "there back"<br />
</code><code><br />
// calculate ends and legs<br />
foreach k in `ways' {<br />
  local ends_`k': list sizeof airports_`k' // all airports of the trip<br />
  local legs_`k'=0<br />
  if `ends_`k''>0 {<br />
    if `ends_`k''==1 &#038; "`airports_`k''"!="same" {<br />
      di as error "You must have at least two airports if you have any."<br />
      error 102<br />
    }<br />
    else if `ends_`k''>1 {<br />
      local legs_`k' =`ends_`k''-1 // trip legs<br />
    }<br />
  }<br />
  if "`k'"=="back" &#038; "`airports_`k''"=="same" {<br />
    foreach w in ends legs {<br />
      local `w'_`k'=``w'_there'<br />
    }<br />
    local airports_`k' "`airports_there'"<br />
  }<br />
}<br />
</code><code><br />
// initialize some locals you'll need later<br />
foreach k in `ways' {<br />
  local layovers_`k'=0<br />
}<br />
</code><code><br />
// final input check<br />
foreach k in `ways' {<br />
  if `legs_`k''>0 {<br />
    forvalues i=1/`legs_`k'' {<br />
      local leg_`i' "leg`i'_`k'"<br />
      local check: list sizeof `leg_`i''<br />
      if `check'!=4 &#038; `check'!=6 &#038; `check'!=8 {<br />
        di as error "check your flight inputs."<br />
        di as error "each should have 4, 6, or 8 words:"<br />
        di as error "airline"           // 1 word<br />
        di as error "flight #"          // 1 word<br />
        di as error "(departure) hh:mm" // 1 word<br />
        di as error "[next day]"        // 2 words<br />
        di as error "(arrival) hh:mm"   // 1 word<br />
        di as error "[next day]"        // 2 words<br />
        error 102<br />
      }<br />
    }<br />
  }<br />
}<br />
</code><code><br />
// calculate cost<br />
foreach k in `ways' {<br />
  local cost_`k'=""<br />
  if `legs_`k''>0 {<br />
    forvalues i=1/`legs_`k'' {<br />
      local thiscost: word `i' of `prices_`k''<br />
      local cost_`k' "`cost_`k''`thiscost'+"<br />
    }<br />
  }<br />
}<br />
local cost=(`cost_there'`cost_back'`otherfees')*`people'<br />
</code><code><br />
// build itinerary lines and calculate layovers<br />
foreach k in `ways' {<br />
  // default layovers: same day<br />
  local layovers_`k'=0<br />
  if `legs_`k''>0 {<br />
  // default arrival date: same as departure date<br />
  local `k'_at_`legs_`k'' "`date_`k''"<br />
    forvalues i=1/`legs_`k'' {<br />
      local from=`i'<br />
      local to=`i'+1<br />
      local input    "`leg`from'_`k''"<br />
      local next_leg "`leg`to'_`k''"<br />
      if "`k'"=="back" {<br />
        local j=`ends_`k''+1-`i'<br />
        local from=`j'<br />
        local to=`j'-1<br />
        local next=`to'-1<br />
        local input "`leg`to'_`k''"<br />
        local next_leg "`leg`next'_`k''"<br />
        local `k'_at_1 "`date_`k''"<br />
      }<br />
      local input_words:  list sizeof input<br />
</code><code><br />
      local leaves_here:  word `from' of `airports_`k''<br />
      local arrives_here: word `to' of `airports_`k''<br />
  </code><code><br />
      local airline:      word `airln'    of `input'<br />
      local flight:       word `flightno' of `input'<br />
      local leaves_time:  word `deptime'  of `input'<br />
      local arrives_time: word 4 of `input'<br />
</code><code><br />
      local layover_from=0 // default arrival,<br />
      local layover_to  =0 // departure and<br />
      local layover_next=0 // connecting flight on same day<br />
</code><code><br />
      // now see if any flight arrives/departs the next day<br />
      if `input_words'==6 {<br />
        local token: word 4 of `input'<br />
        if "`token'"=="next" {<br />
          local layover_from=1 // departure on next day<br />
          local arrives_time: word 6 of `input'<br />
        }<br />
        else {<br />
          local layover_to  =1 // arrival on next day<br />
        }<br />
      }<br />
      if `input_words'==8 {<br />
        local arrives_time: word 6 of `input'<br />
        local layover_from=1 // departure on next day<br />
        local layover_to  =1 // and also arrival on next day<br />
      }<br />
</code><code><br />
      local next: list sizeof next_leg<br />
	if `next'>4 {<br />
        local token: word 4 of `next_leg'<br />
        if "`token'"=="next" {<br />
        local layover_next=1<br />
        }<br />
	}<br />
</code><code><br />
      local layover_arrives=`layover_to'<br />
      local layover_leaves =`layover_from'<br />
</code><code><br />
	// build itinerary line `from'-`to' on leg `k'<br />
      foreach z in leaves arrives {<br />
	  local token ""<br />
	  local plane ""<br />
	  if "`z'"=="leaves" {<br />
          local plane   "`airline' `flight' "<br />
        }<br />
	  if `layover_`z''==1 {<br />
	    local token " next day"<br />
	  }<br />
        local `z'_msg   "`plane'`z' ``z'_here' at ``z'_time'`token'"<br />
      }<br />
</code><code><br />
      local msg           "`leaves_here'_`arrives_here'_label"<br />
	local `msg'         "`leaves_msg' `arrives_msg'"<br />
</code><code><br />
	// now calculate layover at node `to' on leg `k'<br />
      // cumulate all layovers up to this point for correct date<br />
	local layovers_`k' =`layovers_`k''+`layover_from'+`layover_to'<br />
      local date_getthere=td("`date_`k''")+`layovers_`k''<br />
	local date_leavethere=`date_getthere'+`layover_next'<br />
	foreach w in getthere leavethere {<br />
	  local day        =day(`date_`w'')<br />
        local month      =month(`date_`w'')<br />
        local year       =year(`date_`w'')<br />
        local `k'_at_`w' "`day'-`month'-`year'"<br />
	}<br />
      local subtr_this "``k'_at_getthere' `arrives_time'"<br />
      local subtr_from: word `deptime' of `next_leg'<br />
      local subtr_from "``k'_at_leavethere' `subtr_from'"<br />
      foreach z in this from {<br />
        local clock_`z'=clock("`subtr_`z''","DMYhm")<br />
      }<br />
      local minutes=minutes(`clock_from'-`clock_this')<br />
      local `to'_`k'_hours=int(hours(`clock_from'-`clock_this'))<br />
      local `to'_`k'_minutes=`minutes'-``to'_`k'_hours'*60<br />
      local `k'_at_`to' "``k'_at_getthere'"<br />
    }<br />
  }<br />
}<br />
</code><code><br />
// screen output<br />
// #############<br />
</code><code><br />
// display legs in reverse order<br />
// on the way back<br />
</code><code><br />
local go_there "leaving home"<br />
local go_back  "returning"<br />
</code><code><br />
di "length of layovers displayed as [h]h:[m]m"<br />
di ""<br />
foreach k in `ways' {<br />
  if `legs_`k''>0 {<br />
  di ""<br />
  di "`go_`k'' on `date_`k''"<br />
  di ""<br />
    forvalues i=1/`legs_`k'' {<br />
      local from=`i'<br />
      local to=`i'+1<br />
</code><code><br />
	if "`k'"=="back" {<br />
        local j=`ends_`k''-`i'+1<br />
	  local from=`j'<br />
	  local to=`j'-1<br />
	}<br />
</code><code><br />
	local leaves_here:  word `from' of `airports_`k''<br />
      local arrives_here: word `to' of `airports_`k''<br />
      di "``leaves_here'_`arrives_here'_label'"<br />
	if `to'!=1 &#038; `to'!=`ends_`k'' {<br />
        local hrs=``to'_`k'_hours'<br />
        local min=``to'_`k'_minutes'<br />
        di "layover in `arrives_here' -- `hrs':`min' hour(s)"<br />
      }<br />
    }<br />
    di ""<br />
    di "arrive `k' on " %td date("``k'_at_`to''", "DMY")<br />
  }<br />
}<br />
di ""<br />
di "Total cost is $" `cost'<br />
</code><code><br />
end<br />
</code></p>
<p>This program handles multiple legs, departure and arrival on different dates, or one-way trips. It uses Stata's clock functions to calculate layovers accurately, across different days if need be; I prefer mine in whole hours and minutes. Stata's date and time functions recognize either the am/pm format or the 24-hour format. The thing works, as far as I can tell. I tested it with a few bogus itineraries and I had no surprises. The code appears properly indented in my original do-file. You'll have to do that yourself.</p>
<p>One of these days I will send the output straight to e-mail, so I can have my itinerary on my BlackBerry on one clean screenful, maybe two. It would be nice if input were via some web form, with Stata launched in batch mode once the user input is collected. But for now this thing will do for trip planning when I must buy tickets from different places for different legs, not that that happens very often.</p>
<p>Here's the output of the <code>printItinerary</code> Stata command as defined above:</p>
<p><small><em><strong><br />
length of layovers displayed as [h]h:[m]m<br />
</strong><strong><br />
leaving home on 10dec2008<br />
</strong><strong><br />
Delta 6742 leaves RDU at 4:00pm arrives JFK at 6:00pm<br />
layover in JFK -- 2:0 hour(s)<br />
Icelandair 614 leaves JFK at 8:00pm arrives KEF at 6:45am next day<br />
</strong><strong><br />
arrive there on 11dec2008<br />
</strong><strong><br />
returning on 14dec2008<br />
</strong><strong><br />
Icelandair 615 leaves KEF at 5:05pm arrives JFK at 6:10pm<br />
layover in JFK -- 1:0 hour(s)<br />
Delta 6227 leaves JFK at 7:10pm arrives RDU at 9:30pm<br />
</strong><strong><br />
arrive back on 14dec2008<br />
</strong><strong><br />
Total cost is $2094<br />
</strong></em></small></p>
]]></content:encoded>
			<wfw:commentRss>http://enoriver.net/index.php/2008/10/25/cheap-iceland/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
