Flex is driving me CRAZY and I think it's some weird gotcha with how it handles leap years and none leap years. So here's my example. I have the below dateDiff method that finds the number of days or milliseconds between two dates. If I run the following three statements I get some weird issues.
dateDiff("date", new Date(2010, 0,1), new Date(2010, 0, 31));
dateDiff("date", new Date(2010, 1,1), new Date(2010, 1, 28));
dateDiff("date", new Date(2010, 2,1), new Date(2010, 2, 31));
dateDiff("date", new Date(2010, 3,1), new Date(2010, 3, 30));
If you were to look at the date comparisons above you would expect to get 30, 27, 30, 29 as the number of days between the dates. There weird part is that I get 29 when comparing March 1 to March 31. Why is that? Is it something to do with February only having 28 days? If anyone has ANY input on this that would be greatly appreciated.
public static function dateDiff( datePart:String, startDate:Date, endDate:Date ):Number
{
var _returnValue:Number = 0;
switch (datePart) {
case "milliseconds":
_returnValue = endDate.time - startDate.time;
break;
case "date":
// TODO: Need to figure out DST problem i.e. 23 hours at DST start, 25 at end.
// Math.floor causes rounding down error with DST start at dayOfYear
_returnValue = Math.floor(dateDiff("milliseconds", startDate, endDate)/(1000 * 60 * 60 * 24));
break;
}
return _returnValue;
}
This is not a leap year problem, but rather a daylight savings time problem.
To correct the code to account for DST, you need to look at the timezoneOffset of both dates to determine if the date range is spanning a DST boundary.
var adjustment:Number = ( startDate.timezoneOffset - endDate.timezoneOffset ) * 60 * 1000;
_returnValue = endDate.time - startDate.time + adjustment;
This will get the difference between the two time zones (in minutes), convert that value to milliseconds, and then apply the timezone difference to the millisecond difference to "cancel out" the DST boundary.
Naturally, when both numbers are in the same time zone, the adjustment value becomes 0 and the time values are not adjusted.
You have part of the answer in your comment: 2010-Mar-01 0:00 until 2010-Mar-31 0:00 is thirty (!) days minus one hour (because Mar 14 is DST start in 2010). Since you floor the result of your division, you get 29.
Edit: This answer is of course based on the assumption that the time property of Date takes DST into account. This would explain your problem; I didn't check it, however.
Related
hi I has date format and I want converted to correct GMT date :
<YYMMDDhhmmssNNN><C|D|G|H>
Sample value on that date:
210204215026000C
I get this explanation for part NNN :
NNN If flag is C or D then NNN is the number of hours relativeto GMT,
if flag is G or H, NNN is the number of quarter hours relative to GMT
C|D|G|H C and G = Ahead of GMT, D and H = Behind GMT
but I did not get how number of hours relative to GMT can present on 3 digits ? it should be in 2 digit as i knew the offset for hours related to GMT is from 0 to 23 , and also what quarter hours relative to GMT mean ?
I want to use Scala or Java.
I don’t know why they set 3 digits aside for the offset. I agree with you that 2 digits suffice for all cases. Maybe they just wanted to be very sure they would never run of out space, and maybe they even overdid this a bit. 3 digits is not a problem as long as the actual values are within the range that java.time.ZoneOffset can handle, +/-18 hours. In your example NNN is 000, so 0 hours from GMT, which certainly is OK and trivial to handle.
A quarter hour is a quarter of an hour. As Salman A mentioned in a comment, 22 quarter hours ahead of Greenwich means an offset of +05:30, currently used in Sri Lanka and India. If the producer of the string wants to use this option, they can give numbers up to 72 (still comfortably within 2 digits). 18 * 4 = 72, so 18 hours equals 72 quarter hours. To imagine a situation where 2 digits would be too little, think an offset of 25 hours. I wouldn’t think it realistic, on the other hand no one can guarantee that it will never happen.
Java solution: how to parse and convert to GMT time
I am using these constants:
private static final Pattern DATE_PATTERN
= Pattern.compile("(\\d{12})(\\d{3})(\\w)");
private static final DateTimeFormatter FORMATTER
= DateTimeFormatter.ofPattern("uuMMddHHmmss");
private static final int SECONDS_IN_A_QUARTER_HOUR
= Math.toIntExact(Duration.ofHours(1).dividedBy(4).getSeconds());
Parse and convert like this:
String sampleValue = "210204215026000C";
Matcher matcher = DATE_PATTERN.matcher(sampleValue);
if (matcher.matches()) {
LocalDateTime ldt = LocalDateTime.parse(matcher.group(1), FORMATTER);
int offsetAmount = Integer.parseInt(matcher.group(2));
char flag = matcher.group(3).charAt(0);
// offset amount denotes either hours or quarter hours
boolean quarterHours = flag == 'G' || flag == 'H';
boolean negative = flag == 'D' || flag == 'H';
if (negative) {
offsetAmount = -offsetAmount;
}
ZoneOffset offset = quarterHours
? ZoneOffset.ofTotalSeconds(offsetAmount * SECONDS_IN_A_QUARTER_HOUR)
: ZoneOffset.ofHours(offsetAmount);
OffsetDateTime dateTime = ldt.atOffset(offset);
OffsetDateTime gmtDateTime = dateTime.withOffsetSameInstant(ZoneOffset.UTC);
System.out.println("GMT time: " + gmtDateTime);
}
else {
System.out.println("Invalid value: " + sampleValue);
}
Output is:
GMT time: 2021-02-04T21:50:26Z
I think my code covers all valid cases. You will probably want to validate that the flag is indeed C, D, G or H, and also handle the potential DateTimeException and NumberFormatException from the parsing and creating the ZoneOffset (NumberFormatException should not happen).
I'm working to fill an array with High/Low pivot points of the "Previous Trading Day", but I'm facing an issue in terms of the time series (second section below!). I'm not sure if that PineScript's bug or my misunderstanding of how are the time-series functions working!! Please Help, very organize details.
Calling for current Trading Day, then selected the regular session ( No issues in this part )
//------------------ Selected Day of Trading
//Start Day
Start_Period= timestamp(syminfo.timezone, 2020, 12, 09, 00, 00, 00)
//End Day
End_Period = timestamp(syminfo.timezone, 2020, 12, 09, 23, 59, 59)
//------------------ Filtring Session
// Regular Session
t_reg = time("1440", session.regular)
The issue only in this coding box.
Pine script would not recognize the result of Change_Time
// Detect the change of time between selected day trading and most recent day trading (t-t[1])
Change_Time = security(syminfo.tickerid, "1440", change(time))
FunYesterday()=>
if time >= Start_Period-Change_Time and time <= End_Period-Change_Time and t_reg
[pivothigh(close, 3, 2), pivotlow(close, 3, 2)]
However, if I substitute the security function of Change_time= 60*60*24*1000will work fine!!, but I tried to avoid this method because of time deference on weekends, and other holidays.
Final Section find Pivot and Create Array ( No issues in this part )
//------------------ Pivot point at 15 min.
[ph2, pl2] = security(syminfo.tickerid, "15", FunYesterday(), lookahead = barmerge.lookahead_off)
ph2_filter= ph2 == ph2[1]?na:ph2
pl2_filter= pl2 == pl2[1]?na:pl2
//------------------ Array Part
var a = array.new_float()
if (not na(ph2_filter))
array.push(a,ph2_filter)
else if (not na(pl2_filter))
array.push(a,pl2_filter)
if barstate.islast and array.size(a)>0
y=label.new(bar_index, close, "Initial\na: " + tostring(a))
label.delete(y[1])
I'm very open if you have any other idea to import data from the most recent trading day only!!. Thank you
In my angular web application, I want to compare two dates to see if a person is less than 18 years old when she/he entered the company. Here is the code I use to do this:
const dayOfBirth = moment(formControl.value, this.dateFormat, true).startOf('day');
const entranceDateControl = this.wizardFormGroup.get('entranceDate');
const entranceDate = moment(entranceDateControl.value, this.dateFormat, true).startOf('day');
// Check validation rule R3: Age is less than 18 compared to entrance date
const difference = moment.duration(Math.abs(entranceDate.diff(dayOfBirth)));
if (difference.years() < 18) {
const validationMessage = this.getValidationMessage('R3', formControlName);
return validationMessage ? validationMessage.message : null;
}
As you can see, I am using startOf('day') to get rid of any time component so that I only handle dates. I use diff() to get the difference between two dates and then duration() to convert the difference to years, months, days, etc. Using this code, the validation message should NOT show when the person is turning 18 years old on the day when she/he entered the company.
Upon testing this, I came across what is, in my opinion, strange behavior. Depending on months and years used, it gave different results. For instance, for these dates it was Ok:
dayOfBirth = 1998-03-01, 1998-04-01, ..., 2000-02-01
entranceDate = 2016-03-01, 2016-04-01, ..., 2018-02-01
But the following dates returned the validation message:
dayOfBirth = 2000-03-01, 2000-04-01, ..., 2002-02-01
entranceDate = 2018-03-01, 2000-04-01, ..., 2020-02-01
After these dates, i.e. using 2002-03-01 and onward, it works again. I also got wrong result for the dates preceding 1998-03-01.
Now, I had a closer look at the Duration object and I noticed that for the times where it was less than 18 years, it had calculated 864 milliseconds less then when it came to the right conclusion that it was 18 years between the dates.
Correct duration
----------------
dayOfBirth = 1998-03-01, 1998-04-01, ..., 2000-02-01
entranceDate = 2016-03-01, 2016-04-01, ..., 2018-02-01
Duration = 568080000000 ms
Wrong duration
--------------
dayOfBirth = 2000-03-01, 2000-04-01, ..., 2002-02-01
entranceDate = 2018-03-01, 2000-04-01, ..., 2020-02-01
Duration = 567993600000 ms
Duration difference
-------------------
568080000000 - 567993600000 = 86400000 ms = 24 hours = 1 day
Has anyone an explanation for this? Can it be considered a bug in momentjs? Any viable workaround for this?
I didn't go into details in moment source code but it seems duration() is playing tricks with you. Simplify the code and rely only on diffas follow and you should be good (at least it seems to work for the samples you provided). And it's easier on the eyes :)
const moment = require('moment')
const dayOfBirth = moment('2000-03-01').startOf('day');
const entranceDate = moment('2018-03-01').startOf('day');
const difference = entranceDate.diff(dayOfBirth, 'years')
if (difference < 18) {
console.log( '<18')
} else {
console.log( '>=18')
}
will output >=18
We have a solution in Delphi that calculates a travel's duration of a given vehicle, for example, 20 minutes, 25 minutes and so on. However, sometimes we have to antecipate the travel's start time, from a specific datetime, for example 09:00 to 08:40. Then, we need to substract a negative value from a TDateTime variable (travel's start), in this case, something like "-00:20". To do this, we multiply the datetime value by -1 (for example MyDiffDateTimeVariable * -1). The output we got is very strange, sometimes we obtain the exactly opposite behavior. In other case, an operation to extract 20 minutes results in a difference of two days from the original datetime.
Here is a sample console application that simulate our situation, with the current outputs, and what we will expected:
program DateTimeSample;
uses
System.SysUtils, System.DateUtils;
var
LDate1: TDateTime;
LDate2: TDateTime;
begin
LDate1 := IncMinute(0, 20);
LDate2 := IncMinute(0, -20);
WriteLn('Date1: ' + DateTimeToStr(LDate1));
// Output = Date1: 30/12/1899 00:20:00 [OK]
WriteLn('Date2: ' + DateTimeToStr(LDate2));
// Output = Date2: 29/12/1899 23:40:00 [OK]
WriteLn('-----');
WriteLn('Date1: ' + DateTimeToStr(LDate1 * -1));
// Output = Date1: 30/12/1899 00:20:00 [Expected 29/12/1899 23:40:00]
WriteLn('Date2: ' + DateTimeToStr(LDate2 * -1));
// Output = Date2: 31/12/1899 23:40:00 [Expected 30/12/1899 00:20:00]
ReadLn;
end.
When you inspect the value casted to double, you can see:
double(LDate1) = 0.0138888888888889
double(LDate2) = -1.98611111111111
Seems like a bug to me, because with today it returns:
double(LDate1) = 43168,0138888889
double(LDate2) = 43167,9861111111
Edit: Hmm, according the documentation, it is not a bug, it is a feature :-)
When working with negative TDateTime values, computations must handle time portion separately. The fractional part reflects the fraction of a 24-hour day without regard to the sign of the TDateTime value. For example, 6:00 A.M. on December 29, 1899 is –1.25, not –1 + 0.25, which would equal –0.75. There are no TDateTime values from –1 through 0.
Karel's answer explains what's happening. Basically, TDateTime is represented as a Double, but that doesn't mean you can work with it in the same way as you normally would a Double value. It's internal structure carries particular semantics that if you don't handle them correctly, you're bound to get some peculiar behaviour.
The key mistake you're making is in taking the negative of a date-time value. This concept doesn't really make sense. Not even if you look at dates in BC, because the calendar system has changed a number of times over the years.
This is the main reason you should favour library routines that deal with the nuances of the internal structure (whatever your platform). In Delphi that means you should use the SysUtils and DateUtils routines for working with dates and times.
You seem to be trying to hold duration as a TDateTime value. You'd be much better off determining your preferred unit of measure and using Integer (perhaps Int64) or Double (if you need support for fractions of a unit). Then you can add or subtract, preferably using library routines, the duration from your start or end times.
The following code demonstrates some examples.
var
LStartTime, LEndTime: TDateTime;
LDuration_Mins: Integer;
begin
{ Init sample values for each calculation }
LStartTime := EncodeDateTime(2018, 3, 9, 8, 40, 0, 0);
LEndTime := EncodeDateTime(2018, 3, 9, 9, 0, 0, 0);
LDuration_Mins := 20;
{ Output result of each calculation }
Writeln(Format('Whole Duration: %d', [MinutesBetween(LStartTime, LEndTime)]));
Writeln(Format('Frac Duration: %.6f', [MinuteSpan(LStartTime, LEndTime)]));
Writeln(Format('Start Time: %s', [FormatDateTime('yyyy-mm-dd hh:nn:ss', IncMinute(LEndTime, -LDuration_Mins))]));
Writeln(Format('End Time: %s', [FormatDateTime('yyyy-mm-dd hh:nn:ss', IncMinute(LStartTime, LDuration_Mins))]));
end;
Additional Considerations
You said you're dealing with vehicle travel times. If you're dealing with long-haul travel you might have some other things to think about.
Daylight saving: If a vehicle starts its journey shortly before DST changes and ends after, you need to take this into account when calculating a missing value. Perhaps easiest would be to convert date-time values to UTC for the calculation. Which leads to...
Time zone changes: Again, unless your code is time-zone aware you're bound to make mistakes.
Compiler always appears to treat TDateTime as positive when doing numerical operations on it. Try this:
uses
System.SysUtils, System.DateUtils;
function InvertDate(ADateTime: TDateTime): TDateTime;
var
LMsec: Int64;
begin
LMsec := MillisecondsBetween(ADateTime, 0); //Always Positive
if ADateTime > 0 then
LMsec := 0 - LMsec;
Result := IncMillisecond(0, LMsec);
end;
var
LDate1: TDateTime;
LDate1Negative: TDateTime;
LDate2: TDateTime;
begin
try
LDate1 := IncMinute(0, 20);
LDate2 := IncMinute(0, -20);
WriteLn('Date1: ' + DateTimeToStr(LDate1));
// Output = Date1: 30/12/1899 00:20:00 [OK]
WriteLn('Date2: ' + DateTimeToStr(LDate2));
// Output = Date2: 29/12/1899 23:40:00 [OK]
WriteLn('-----');
WriteLn('Date1: ' + DateTimeToStr( InvertDate(LDate1) ));
// Output = Date1: Expected 29/12/1899 23:40:00
WriteLn('Date2: ' + DateTimeToStr( InvertDate(LDate2) ));
// Output = Date2: 30/12/1899 00:20:00
ReadLn;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
I'm trying to get the difference between 2 dates in days, hours, and seconds:
import groovy.time.*
Date now = new Date()
// Using deprecated constructor just for this example
Date newYearsDay2000 = new Date(2000, 0, 1)
use (TimeCategory) {
now - newYearsDay2000
}
This prints:
-690023 days, -14 hours, -38 minutes, -27.182 seconds
Which is obviously nothing like the difference between today's date and 2000/1/1, where am I going wrong?
Thanks,
Don
Could be an issue with the deprecated constructor?
If you use Calendar (and the Groovy updated method) to create the newYearsDay2000 var, you get:
import groovy.time.*
import static java.util.Calendar.*
Date now = new Date()
// Use the static imported Calendar class
Date newYearsDay2000 = instance.updated( year:2000, month:JANUARY, day:1 ).time
use( TimeCategory ) {
now - newYearsDay2000
}
which gives the result:
3925 days, 23 hours, 59 minutes, 59.999 seconds
Edit
Yeah, the JavaDoc for Date shows that constructor with the comment:
Date(int year, int month, int date)
Deprecated. As of JDK version 1.1, replaced by Calendar.set(year + 1900, month, date) or GregorianCalendar(year + 1900, month, date).
Which leads me to believe that:
Date newYearsDay2000 = new Date(2000, 0, 1)
Is actualy creating the Date for new Years Day in the year 3900
Date
Parameters:
year - the year minus 1900.