I need a faster implementation of FractionOfYear
and FractionOfMonth
, which do the following:
Input: A time/date specified by {y_, m_, d_, h_, n_, s_}
Output: A real number from 0 to 1 representing the fraction of the year or month that the given time/date spec occurs in.
Leap days and leap seconds complicate things, so I thought I could just rely on DateDifference
, but it is too slow:
RandomDateList[] := {RandomInteger[{1800, 2100}], RandomInteger[{1, 12}], RandomInteger[{1, 28}], RandomInteger[{0, 23}], RandomInteger[{0, 59}], RandomInteger[{0, 59}]};
RandomDates[n_] := Table[RandomDateList[],{n}]
secondOfYear[{y_, m_, d_, h_, n_, s_}] :=
First[DateDifference[{y - 1, 12, 31, 24, 0, 0}, {y, m, d, h, n, s},
"Second"]] / First[DateDifference[{y - 1, 12, 31, 24, 0, 0}, {y, 12, 31, 24, 0, 0}, "Second"]]
secondOfMonth[{y_, m_, d_, h_, n_, s_}] := First[DateDifference[{y, m, 1, 0, 0, 0},
{y, m, d, h, n, s}, "Second"]]/First[DateDifference[{y, m, 1, 0, 0, 0}, If[m==12, {y+1, 1, 1, 0, 0, 0}, {y, m+1, 1, 0, 0, 0}], "Second"]]
AbsoluteTiming [secondOfYear /@ RandomDates[1000]]
takes 6 seconds.
There must be a faster easier way of doing this! I'll accept the first answer that takes under a second for 100,000 elements.
Answer
Ok, Java solution, by popular demand.
Solution
Load the Java reloader
Compile this class:
JCompileLoad@
"import java.util.Calendar;
public class SecondOfYearVectorized{
public static double[] secondOfYear(int[][] dates){
Calendar calendar = Calendar.getInstance();
double[] result = new double[dates.length];
for(int i=0;icalendar.set(dates[i][0],dates[i][1]-1,dates[i][2],
dates[i][3], dates[i][4],dates[i][5]);
long time = (long) (calendar.getTimeInMillis()/1000);
calendar.set(dates[i][0]-1,11,31,24,0,0);
long timepy = (long) (calendar.getTimeInMillis()/1000);
calendar.set(dates[i][0],11,31,24,0,0);
long timey = (long) (calendar.getTimeInMillis()/1000);
result[i]= ((double)(timepy-time))/(timepy-timey);
}
return result;
}
}"
Usage and comparisons
dates = RandomDates[100000];
SecondOfYearVectorized`secondOfYear[dates]//Short//AbsoluteTiming
{0.2460938,{0.310529,0.0296395,<<99996>>,0.0393697,0.0470913}}
N[secondOfYear2 /@ dates]//Short//AbsoluteTiming
{1.5937500,{0.310643,0.0296395,<<99996>>,0.0393697,0.0470913}}
Remarks
The Java solution seems about 6 times faster than Brett's one, and about 4 times faster than the fastest vectorized solution I could cook up with AbsoluteTime
. The AbsoluteTime
itself is pretty fast though, so I don't know to what should I attribute the speed-up (my guess is that I save on data transfer, which causes a performance hit, since I only transfer data once. And probably Java Calendar-based functionality is still faster by itself). Note that results obtained with Java and Mathematica solution are only approximately the same, but the differences are quite small, when any. Note also that Java solution reaches full speed after several runs, likely due to a warm-up of JVM HotSpot JIT compiler.
Comments
Post a Comment