1
$\begingroup$

I have the starting and ending dates and times. And I need to calculate the night time in this period (from 10 pm (22) to 6 am (6)).
Example:
starting date and time is {2015, 1, 4, 3, 10}
ending date and time is {2015, 3, 4, 18, 10}
Total (this is the result of function)= 1090 min (18 h 10 min)

How can I do this?

Thanks! enter image description here

$\endgroup$
  • $\begingroup$ your example results are not correct (?) else I don't understand the question, i get more like 500h. $\endgroup$ – george2079 Apr 9 '15 at 21:44
  • $\begingroup$ do you need to be accurate if there is a daylight savings offset in the range? $\endgroup$ – george2079 Apr 9 '15 at 21:55
  • $\begingroup$ no, I don't. it doesn't matter. $\endgroup$ – V_kid Apr 9 '15 at 21:59
  • $\begingroup$ starting date and time is {2015, 1, 4, 3, 10} = {year, day, month, hour, minutes} $\endgroup$ – V_kid Apr 9 '15 at 22:13
  • $\begingroup$ That's why I get like 18h but you more 500h I tried to use your code and it didn't work correct: didn't calculate nightfirstpart And for example I will have the ending date and time like this {2015, 3, 4, 22, 10}. In this case I need to take in account 10 minutes after 22 (10 pm). $\endgroup$ – V_kid Apr 9 '15 at 22:22
4
$\begingroup$
d1 = {2015, 4, 1, 3, 10};
d2 = {2015, 4, 3, 18, 10};
j[d_, s_, h_] := Join[DatePlus[d, s][[1 ;; 3]], {h, 00}]
abst = AbsoluteTime;
l1 = DateRange[j[d1, -2, 22], j[d2, 2, 22]];
l2 = DateRange[j[d1, -1, 6], j[d2, 3, 6]];
ints = Interval /@ Map[abst, Transpose@{l1, l2}, {2}];
iu = IntervalUnion@@(IntervalIntersection[Interval[abst/@{d1,d2}], #] & /@ ints);
res = DateList @@ ((Differences /@ (List @@ iu) // Total));
DateDifference[{1900, 1, 1}, res, "Minute"]
(* {1130, "Minute"} *)

Note that your arithmetic is wrong and you're interchanging the month and day places in your lists

$\endgroup$
  • $\begingroup$ You're absolutely right. My arithmetic is wrong. It should be 18 h 50 m. Your code works correct! Thank you! Can you help me to get the answer just in minutes? $\endgroup$ – V_kid Apr 9 '15 at 22:32
  • $\begingroup$ @V_kid There you've it $\endgroup$ – Dr. belisarius Apr 9 '15 at 22:48
1
$\begingroup$

Edit, fixing some errors to show this "works"

 tend = AbsoluteTime[{2015, 4, 3, 18, 10}];
 deltimed = (tend - AbsoluteTime[{2015, 4, 1, 3, 10}])/3600/24;
 {wholedays, fractionseconds} = 
     {Floor[#], FractionalPart[#] 24 3600 } & @ deltimed;
 isnight[t_?NumericQ] := Boole[0 <= # < 6 || # >= 22] &@DateList[t][[4]];
 nightfirstpartday = 
      NIntegrate[isnight[t], {t, tend - fractionseconds, tend}]/3600 // 
                Quiet;
 answer = wholedays 8 + nightfirstpartday

18.8332

 {Quantity[Floor[#], "Hours"], 
   Quantity[60 FractionalPart[#], "Seconds"]} & @ answer

{Quantity[18, "Hours"], Quantity[49.9931, "Seconds"]}

slow and inelegant.. but it does work.

Note you can in principle get the result in one shot like this:

 NIntegrate[isnight[t],
      {t, AbsoluteTime[{2015, 4, 1, 3, 10}], 
         AbsoluteTime[{2015, 4, 3, 18, 10}]}]/3600 // Quiet

This will severely loose accuracy if the time span is more than a few days however.

$\endgroup$
1
$\begingroup$

Night time of First day + (night time period times [[2;;-2]] days) + night time of Last day

nightTime[{startDateTime_?DateObjectQ, endDateTime_?DateObjectQ}, {nightStartTime_?TimeObjectQ, nightEndTime_?TimeObjectQ}] :=
(* night time of First day + night time period \[Times] [[2;;-2]] \days + night time of Last day *)
 Simplify[
  Max[TimeObject[startDateTime] - nightStartTime, nightEndTime - TimeObject[startDateTime], Quantity[0, "Seconds"]] + 
   Max[(QuantityMagnitude@Floor@UnitConvert[endDateTime - startDateTime, "Days"] - 2)*
    ((TimeObject[{23, 59, 59}] - nightStartTime) + (nightEndTime - TimeObject[{0, 0, 0}])), Quantity[0, "Seconds"]] +
   If[(startDateTime - TimeObject[startDateTime]) == (endDateTime - TimeObject[endDateTime]),
    Max[TimeObject[endDateTime] - nightStartTime, nightEndTime - TimeObject[endDateTime], Quantity[0, "Seconds"]],
    Quantity[0, "Seconds"]
  ]
 ]

Let

start = DateObject@{2015, 1, 4, 3, 10};
end = DateObject@{2015, 3, 4, 18, 10};
nightStart = TimeObject[{22, 00}];
nightEnd = TimeObject[{6, 00}];

Then

timePeriod = nightTime[{start, end}, {nightStart, nightEnd}];
UnitConvert[timePeriod, "Hours"]
(* Quantity[458.818, "Hours"] *)

Hope this helps.

*Updated to account for date range less than 3 days *

Now end = DateObject@{2015, 1, 4, 18, 10}; and nightTime[{start, end}, {nightStart, nightEnd}] will work.

$\endgroup$
  • $\begingroup$ There is an assumption in this function that the time span is at least 3 days long but it is very easy to modify this by not accepting a negative for the middle days and comparing the date only part of startDateTime and endDateTime. $\endgroup$ – Edmund Apr 10 '15 at 1:10
  • $\begingroup$ You ought to fix this to show the result with the corrected time spec. $\endgroup$ – george2079 Apr 10 '15 at 14:11
  • $\begingroup$ @george2079 Yup. Done. $\endgroup$ – Edmund Apr 10 '15 at 16:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.