#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 11 years ago by mLipok
comment:2 Changed 11 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 11 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 11 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 11 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 11 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.