#3002 closed Bug (No Bug)
Bug - _DateAdd('s', 1, '1970/01/01') Returns '1970/01/01'
Reported by: | mLipok | Owned by: | |
---|---|---|---|
Milestone: | Component: | Standard UDFs | |
Version: | 3.3.13.19 | Severity: | None |
Keywords: | Cc: |
Description
Repro:
#include <Date.au3> ConsoleWrite(@CRLF) ; positive results _DateAdd_TEST('1970/01/01 00:00:00') ; negative results _DateAdd_TEST('1970/01/01') ; positive results _DateAdd_TEST_2('1970/01/01') Func _DateAdd_TEST($sDate) $sDate = _DateAdd('s', 1, $sDate) ConsoleWrite('@error = ' & @error & @CRLF) ConsoleWrite($sDate & @CRLF) ConsoleWrite(@CRLF) EndFunc ;==>_DateAdd_TEST Func _DateAdd_TEST_2($sDate) If StringRegExpReplace($sDate, '(\d{4}\/\d{2}\/\d{2})', '') = '' Then $sDate &= ' 00:00:00' $sDate = _DateAdd('s', 1, $sDate) ConsoleWrite('@error = ' & @error & @CRLF) ConsoleWrite($sDate & @CRLF) ConsoleWrite(@CRLF) EndFunc ;==>_DateAdd_TEST_2
solusion proposal:
new internal function:
Func __DateExpand(Byref $sDate) If StringRegExpReplace($sDate, '(\d{4}\/\d{2}\/\d{2})', '') = '' Then $sDate &= ' 00:00:00' EndFunc ;==>__DateExpand
and modyfication:
Func _DateAdd($sType, $iNumber, $sDate) Local $asTimePart[4] Local $asDatePart[4] Local $iJulianDate ; Verify that $sType is Valid $sType = StringLeft($sType, 1) If StringInStr("D,M,Y,w,h,n,s", $sType) = 0 Or $sType = "" Then Return SetError(1, 0, 0) EndIf ; Verify that Value to Add is Valid If Not StringIsInt($iNumber) Then Return SetError(2, 0, 0) EndIf __DateExpand($sDate) ; Verify If InputDate is valid If Not _DateIsValid($sDate) Then Return SetError(3, 0, 0) EndIf ; split the date and time into arrays _DateTimeSplit($sDate, $asDatePart, $asTimePart) ; ==================================================== ; adding days then get the julian date ; add the number of day ; and convert back to Gregorian If $sType = "d" Or $sType = "w" Then If $sType = "w" Then $iNumber = $iNumber * 7 $iJulianDate = _DateToDayValue($asDatePart[1], $asDatePart[2], $asDatePart[3]) + $iNumber _DayValueToDate($iJulianDate, $asDatePart[1], $asDatePart[2], $asDatePart[3]) EndIf ; ==================================================== ; adding Months If $sType = "m" Then $asDatePart[2] = $asDatePart[2] + $iNumber ; pos number of months While $asDatePart[2] > 12 $asDatePart[2] = $asDatePart[2] - 12 $asDatePart[1] = $asDatePart[1] + 1 WEnd ; Neg number of months While $asDatePart[2] < 1 $asDatePart[2] = $asDatePart[2] + 12 $asDatePart[1] = $asDatePart[1] - 1 WEnd EndIf ; ==================================================== ; adding Years If $sType = "y" Then $asDatePart[1] = $asDatePart[1] + $iNumber EndIf ; ==================================================== ; adding Time value If $sType = "h" Or $sType = "n" Or $sType = "s" Then Local $iTimeVal = _TimeToTicks($asTimePart[1], $asTimePart[2], $asTimePart[3]) / 1000 If $sType = "h" Then $iTimeVal = $iTimeVal + $iNumber * 3600 If $sType = "n" Then $iTimeVal = $iTimeVal + $iNumber * 60 If $sType = "s" Then $iTimeVal = $iTimeVal + $iNumber ; calculated days to add Local $iDay2Add = Int($iTimeVal / (24 * 60 * 60)) $iTimeVal = $iTimeVal - $iDay2Add * 24 * 60 * 60 If $iTimeVal < 0 Then $iDay2Add = $iDay2Add - 1 $iTimeVal = $iTimeVal + 24 * 60 * 60 EndIf $iJulianDate = _DateToDayValue($asDatePart[1], $asDatePart[2], $asDatePart[3]) + $iDay2Add ; calculate the julian back to date _DayValueToDate($iJulianDate, $asDatePart[1], $asDatePart[2], $asDatePart[3]) ; caluculate the new time _TicksToTime($iTimeVal * 1000, $asTimePart[1], $asTimePart[2], $asTimePart[3]) EndIf ; ==================================================== ; check if the Input day is Greater then the new month last day. ; if so then change it to the last possible day in the month Local $iNumDays = _DaysInMonth($asDatePart[1]) ; If $iNumDays[$asDatePart[2]] < $asDatePart[3] Then $asDatePart[3] = $iNumDays[$asDatePart[2]] ; ======================== ; Format the return date $sDate = $asDatePart[1] & '/' & StringRight("0" & $asDatePart[2], 2) & '/' & StringRight("0" & $asDatePart[3], 2) ; add the time when specified in the input If $asTimePart[0] > 0 Then If $asTimePart[0] > 2 Then $sDate = $sDate & " " & StringRight("0" & $asTimePart[1], 2) & ':' & StringRight("0" & $asTimePart[2], 2) & ':' & StringRight("0" & $asTimePart[3], 2) Else $sDate = $sDate & " " & StringRight("0" & $asTimePart[1], 2) & ':' & StringRight("0" & $asTimePart[2], 2) EndIf EndIf ; Return $sDate EndFunc ;==>_DateAdd
Attachments (0)
Change History (6)
comment:1 Changed 10 years ago by mLipok
comment:2 Changed 10 years ago by jchd
I'm not sure this qualifies as 'bug' and I'd rather see this as a feature request, for when you supply a date only (without time), that doesn't always imply that you mean time = '00:00:00'. Yet commonly used library functions work the way to want and consider a default time part to be '00:00:00'.
BTW if ever this is accepted, I'd like other would also consider another modification. Currently the function only works when the date separator is a slash (/), but the standard separator specified by ISO 8601 is a dash (-). It would be pretty beneficial to simply mask off the separator in the regexp, yet take care to use the same separator in output.
; this should definitely work _DateAdd('s', 1, '2015-03-21')
The same change should be made to related _Date* functions, like _DateDiff and some others. The best witness that this change is indeed needed is that _DateIsValid accepts both separators!
Note: I don't advocate to accept any more format variant described in ISO 8601.
comment:3 Changed 10 years ago by guinness
jchd,
It does accept - (see the StringSplit() in _DateTimeSplit()
#include <Date.au3> ConsoleWrite(_DateAdd('s', 1, '2015-03-21 00:00:00') & @CRLF)
Unless you meant the output should be 2015-03-21 00:00:01 and not 2015/03/21 00:00:00
comment:4 Changed 10 years ago by jchd18
Oops, I never read the help file down to the last Remark line.
BTW, this important remark about allowable date formats would be better placed in the $Date parameter description: "Input date in the format YYYY/MM/DD[ HH:MM:SS]" --> "Input date in any format described in _DateTimeSplit()".
Sorry for the noise, but yes I still find it would be natural to expect the function to return dates under the same format used for input.
comment:5 Changed 10 years ago by Melba23
- Resolution set to No Bug
- Status changed from new to closed
I am going to close this. It seems illogical to me that the function should deal with adding/subtracting an interval smaller than the lowest interval defined in the DTG passed to it. If the user wants to add/subtract a time interval they need to define the start time, not expect the function to default to some arbitrary value.
M23
comment:6 Changed 10 years ago by mLipok
After deliberation, I have to agree with your opinion, and also to ask you to consider, adding an appropriate description for the Help documentation, because this was not clear for me so can be not clear for others, especialy non native english coders.
Guidelines for posting comments:
- You cannot re-open a ticket but you may still leave a comment if you have additional information to add.
- In-depth discussions should take place on the forum.
For more information see the full version of the ticket guidelines here.
Modyfication I mean only by appropriate use this new internal function.