A Day-of-Year Calculator with Python

Many seismic data are stored using a numerical day of the year in place of a month and day. This is efficient for the data storage, but it leads to the need to convert back and forth from command month-day to day-of-year values. Over the years, I have seen printed tables of values that some seismologists kept nearby to do the conversion back and forth. Now, of course, we work at computers much of the day and we generally have an interactive terminal available, so I created a simple python utility to perform the conversion.

Modern python has extensive packages to deal with time quantities, but I use a simple, lightweight package that I wrote to handle the conversions (back in the mid 90’s when python had many fewer packages and most everyone was using PERL).

The date to day-of-year conversion is relatively straight forward, so there’s not much code to write – here is what I use.

doy.py

!/usr/bin/python
import sys,string
import pytutil
#
if len(sys.argv) == 4:
	
	month = string.atoi(sys.argv[1])
	day   = string.atoi(sys.argv[2])
	year  = string.atoi(sys.argv[3])
	
	print "   %02d/%02d/%04d is the %03d of the year." \
		  % (month,day,year,cja_pytutil.doy(year,month,day))
elif len(sys.argv) == 3:
	doy   = string.atoi(sys.argv[1])
	year  = string.atoi(sys.argv[2])
	output = cja_pytutil.monthdate(year,doy)
	print "   Day %03d of %4d is %02d/%02d/%04d " \
		  % (doy,year,output[0],output[1],year,)
else:
	print " "
	print "  Usage: month day year"
	print "      or"
	print "  Usage: doy year"
	print " "	

cja_pytutil

Here is the package, cja_pytutil. It consists of a few simple functions that have obvious usage.

#!/usr/local/bin/python
#
########################################################
#
def is_leap_year(year):
	isleap = 0
	i0 = year % 4
	i1 = year % 100
	i2 = year % 400
	if ((i0 == 0 and i1 != 0) or i2 == 0):
	  isleap = 1
	#
	return(isleap)
########################################################
#
def ndaysinyear(year):
	if (is_leap_year(year) == 1):
	  return(366)
	return(365)
#
########################################################
#
def doy(y,m,d):
	#
	day = int(d)
	#
	if m == 1:
		return(day)
	#
	nd = [31,28,31,30,31,30,31,31,30,31,30,31]
	#
	if (is_leap_year(y) == 1):
	  nd[1] = 29
	#
	for i in range(int(m) - 1):
	  day = day + nd[i]
	#
	return(day)
#
########################################################
#
def monthdate(year,day):
	ok = -1
	if(day > ndaysinyear(year)):
		return([0,0,ok])
	#
	nd = [31,28,31,30,31,30,31,31,30,31,30,31]
	if (is_leap_year(year) == 1):
	  nd[1] = 29
	d = day
	#
	m = 1
	ok = 1
	for i in range(12):
		if ( d <= nd[i]):
			date = d
			return([m, date, ok])
		m = m + 1
		d = d - nd[i]
	ok = -1
	return([0,0,ok])
#
########################################################
#
def yd2seconds(y,d):
	ok = 1
	y0 = 1970
	y1 = y - y0
	ndays = 0
	for iy in range(y0,y):
		ndays = ndays + ndaysinyear(iy)
	ndays = ndays + d
	nseconds = ndays * 24 * 60 * 60
	return([nseconds, ok])
#
########################################################
#
def dt2seconds(y,d,h,m,s):
	ok = 1
	nseconds = yd2seconds(y,d)[0] + h*60*60 + m*60 + s
	return([nseconds, ok])
		

Execution is simple, no arguments produces a simple usage statement, two arguments indicates conversion form day-of-year and year to month-day-year, and three arguments indicates a conversion from month-day-year to day-of-year and year.

~ > doy 4 18 1906
   04/18/1906 is the 108 of the year.
~ > doy 108 1906
   Day 108 of 1906 is 04/18/1906 

I used the simple functions in other scripts that read and manipualte seismograms stored in SAC format. But doy is a handy utility.