Jump to content

GUICtrlCreateDate using every quarter hour only


Recommended Posts

Is there a make GUICtrlCreateDate go up/down by 15 minutes at a time when a user presses the up/down arrow?  If a user types "08:05", that it will round down to "08:00"?
If a user types "08:10", that it will round down to "08:15"?
If a user types "08:55", that it will round down to "09:00"?

 

$time = GUICtrlCreateDate("08:00", 25, 200, 230, 28, BitOR($DTS_UPDOWN, $DTS_TIMEFORMAT))

 

Thanks for any help you can give!

Link to post
Share on other sites
  • Moderators
Posted (edited)

zuladabef,

This works when both the UpDown and direct user input is used to change the minutes:

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <Date.au3>

Example()

Func Example()
    GUICreate("My GUI get time", 200, 200, 800, 200)

    ; Get current time
    $sTime = _NowTime(4)
    $iHour = Int(StringLeft($sTime, 2))
    $iMins = Int(StringRight($sTime, 2))
    ; Set to nearest quarter
    Switch $iMins
        Case 53 To 59, 01 To 07
            $iMins = 0
        Case 08 To 22
            $iMins = 15
        Case 23 To 37
            $iMins = 30
        Case 38 To 52
            $iMins = 45
    EndSwitch

    Local $idDate = GUICtrlCreateDate("", 20, 20, 100, 20, BitOR($DTS_UPDOWN, $DTS_TIMEFORMAT))
    GUICtrlSendMsg($idDate, $DTM_SETFORMATW, 0, "HH:mm")
    GUICtrlSetData($idDate, _NowCalcDate() & StringFormat(" %02i:%02i:00", $iHour, $iMins))

    GUISetState(@SW_SHOW)

    Local $iHour, $iQuart, $sDate
    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop
            Case $idDate

                ; In case we need to alter the hour too
                $iHourChange = 0
                ; Read minutes
                $iMins = Int(StringRight(GUICtrlRead($idDate), 2))
                ; Set minutes to next quarter - depending on direction of movement
                Switch $iMins
                    Case 1 To 13
                        $iMins = 15
                    Case 16 To 28
                        $iMins = 30
                    Case 31 To 43
                        $iMins = 45
                    Case 46 To 58
                        $iMins = 00
                        $iHourChange = +1
                    Case 02 To 14
                        $iMins = 00
                        $iHourChange = -1
                    Case 17 To 29
                        $iMins = 15
                    Case 32 To 44
                        $iMins = 30
                    Case 47 To 59
                        $iMins = 45
                EndSwitch
                ; Read hour
                $iHour = Int(StringLeft(GUICtrlRead($idDate), 2))
                ; Set new time
                $sDate = _NowCalcDate() & StringFormat(" %02i:%02i:00", $iHour + $iHourChange, $iMins)

                GUICtrlSetData($idDate, $sDate)

        EndSwitch
    WEnd
EndFunc   ;==>Example

I am now looking into how to deal with direct user input.

Looks like it was easier then I thought it might be!

M23

Edited by Melba23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to post
Share on other sites

@Melba23  I am having a similar problem with my code.  If user enter manually 16 as minute, your code move it to 30 but it should be rounded to 15.  So we need to figure out if user has enter time manually or if he has clicked arrows or use keyboard...

Link to post
Share on other sites

Found a way, not the nicest but it is working for all type of entry (manual, keyboard, and left click on arrow):

#include <DateTimeConstants.au3>
#include <GUIConstantsEx.au3>
#include <MsgBoxConstants.au3>
#include <Date.au3>
#include <Misc.au3>

Example()

Func Example()
  GUICreate("My GUI get time", 200, 200, 800, 200)
  Local $idDate = GUICtrlCreateDate("", 20, 20, 100, 20, BitOR($DTS_UPDOWN, $DTS_TIMEFORMAT))
  GUICtrlSendMsg($idDate, $DTM_SETFORMATW, 0, "HH:mm")
  GUISetState(@SW_SHOW)
  SetTime($idDate)

  While 1
    Switch GUIGetMsg()
      Case $GUI_EVENT_CLOSE
        ExitLoop
      Case $idDate
        If Mod(Int(StringRight(GUICtrlRead($idDate), 2)), 15) Then
          If _IsPressed("26") Or _IsPressed("28") Or _IsPressed("01") Then
            SetTime($idDate, True)
          Else
            SetTime($idDate)
          EndIf
        EndIf
    EndSwitch
  WEnd
EndFunc   ;==>Example

Func SetTime($idDate, $bVal = False)
  Local $iHour = Int(StringLeft(GUICtrlRead($idDate), 2))
  Local $iMin = Int(StringRight(GUICtrlRead($idDate), 2))
  Local $iDir = 0
  If $bVal Then
    $iDir = Mod($iMin, 5) = 4 ? -1 : +1
    $iMin += $iDir * 14
  Else
    $iMin = Round($iMin/15) * 15
  EndIf
  If $iMin = 45 And $iDir < 0 Then $iHour = Mod($iHour+23, 24)
  If $iMin = 60 Then
    $iHour = Mod($iHour + 1, 24)
    $iMin = 0
  EndIf
  Local $sDate = _NowCalcDate() & StringFormat(" %02i:%02i:00", $iHour, $iMin)
  ConsoleWrite ($sDate & @CRLF)
  GUICtrlSetData($idDate, $sDate)
EndFunc   ;==>SetTime

I will see if I can register some messages to capture the type of user input...to be followed.

Edited by Nine
As per M23 suggestion below
Link to post
Share on other sites
4 minutes ago, Nine said:

Found a way,

I don't know why but the arrows buttons and the arrow keys only increment by 1 when I run your code.

Am I doing something wrong?

It does print to the Console when trying it:

4/30/2021 12:15:00
4/30/2021 13:30:00
4/30/2021 13:31:00
4/30/2021 13:32:00
4/30/2021 13:05:00
4/30/2021 13:32:00
4/30/2021 13:31:00
4/30/2021 13:30:00
4/30/2021 13:00:00
4/30/2021 13:27:00
4/30/2021 13:00:00
4/30/2021 13:00:00
4/30/2021 13:27:00
4/30/2021 13:26:00
4/30/2021 13:25:00
4/30/2021 13:24:00
4/30/2021 13:-5:00
4/30/2021 13:22:00
4/30/2021 13:21:00
4/30/2021 13:20:00
4/30/2021 13:21:00
4/30/2021 13:22:00
4/30/2021 13:-5:00
4/30/2021 13:24:00

 

Code hard, but don’t hard code...

Link to post
Share on other sites
  • Moderators

Nine,

I was looking for a way to distinguish user input between direct entry and the UpDown, but I could not find a suitable message so i went for the simple method. I am still working on making the distinction.

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to post
Share on other sites
  • Moderators

Nine,

If I change _NowDate to _NowCalcDate your code works for me. It seems you need the formal YYYY/MM/DD format for the GUICtrlSetData to work regardless of local settings.

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to post
Share on other sites
Posted (edited)
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <Date.au3>
#include <Misc.au3>

Global $roundof_by = 15
Example()

Func Example()
    GUICreate("My GUI get time", 200, 200, 800, 200)

    Local $sMultiplier = -1
    Local $sDate = _NowCalcDate()
    Local $sTime = _NowTime(4)
    Local $setDate = __GetDate($sDate, $sTime)

    Local $idDate = GUICtrlCreateDate("", 20, 20, 100, 20, BitOR($DTS_UPDOWN, $DTS_TIMEFORMAT))
    GUICtrlSendMsg($idDate, $DTM_SETFORMATW, 0, "HH:mm")
    GUICtrlSetData($idDate, $setDate)
    GUISetState(@SW_SHOW)

    Local $Read_Input, $diff_Check
    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop
            Case $idDate
                $Read_Input = GUICtrlRead($idDate)
                $sDate = StringLeft($setDate, 10)
                If _IsPressed("26") Or _IsPressed("28") Or _IsPressed("01") Then
                    $Read_Input = $sDate & ' ' & $Read_Input & ':00'
                    $diff_Check = _DateDiff('n', $setDate, $Read_Input)
                    If (mod($diff_Check, 60) = 0) Or (mod($diff_Check, 60) = -0) Then $roundof_by = 60
                    If (($diff_Check >= 1) And ($diff_Check <> 59) And ($diff_Check <> 1380)) Or ($diff_Check = -1380) Then $sMultiplier = 1
                        $setDate = _DateAdd('n', $sMultiplier * $roundof_by, $setDate)
                Else
                    $setDate = __GetDate($sDate, $Read_Input)
                Endif
                GUICtrlSetData($idDate, $setDate)
                $roundof_by = 15
                $sMultiplier = -1
        EndSwitch
    WEnd
EndFunc   ;==>Example

Func __GetDate($sDate, $sTime)
Local $iHour = StringLeft($sTime, 2)
Local $iMins = StringFormat("%.2f", (Round((StringRight($sTime, 2))  / $roundof_by) * $roundof_by) / 100)
  If StringRight($iMins, 2) = 60 Then
    $iHour = Mod($iHour + 1, 24)
    $iMins= 0
  EndIf
Return $sDate & StringFormat(" %02i:%02i:00", $iHour, StringRight($iMins, 2))
EndFunc

 

Edited by jugador
Link to post
Share on other sites
Posted (edited)

@jugador

Your code has a flaw.  When you are positioned on the hours and you press arrow keys or click arrow buttons, the minutes are changing but not the hours.  It should be the contrary.  When position on hours and using arrows, the hours should change by 1 (up/down) and minutes should stay same.

Edited by Nine
Link to post
Share on other sites
On 4/30/2021 at 8:11 PM, zuladabef said:

GUICtrlCreateDate go up/down by 15 minutes at a time when a user presses the up/down arrow?

@Nine  That was intentional but looks like I misread his quote. I updated my previous post.

Link to post
Share on other sites

This example function, _TimeRound(), will round up or down the time to the nearest specified minute in an hour, or, to a fraction of a minute. The default rounding number is 15 minute.

#include <Date.au3>
; https://www.autoitscript.com/forum/topic/205759-guictrlcreatedate-using-every-quarter-hour-only/

ConsoleWrite("_TimeRound(""12:07"")   equals      " & _TimeRound("12:07") & "  ; Note: There are no 'return' seconds present." & @CRLF)
ConsoleWrite("_TimeRound(""12:8"")    equals      " & _TimeRound("12:8") & @CRLF)

For $i = 0 To 68 * 60
    Local $sTimeIncrement = StringRegExpReplace(_DateAdd('s', $i, "2021/04/02 12:00:00"), "(^\H+)\h", "")
    ConsoleWrite("_TimeRound(""" & $sTimeIncrement & """)   equals   " & _TimeRound($sTimeIncrement) & @tab)
    ConsoleWrite("_TimeRound(""" & $sTimeIncrement & """, 15/60)   equals   " & _TimeRound($sTimeIncrement, 15/60) & @CRLF)
Next


; Description - Rounds time (default nearest 15 minutes of the hour, or, closest 15mins to $sTime +/- 7.5 mins).
; Parameters - $sTime          - A time string, format in HH:MM[:SS]
;              $iRoundedInMins - Rounding $sTime in minutes (default 15mins). For rounding to 15 seconds, have $iRoundedInMins = 15/60 (minutes).
; Returns - Time to nearest 15 mins in format HH:(00|15|30|45)[:00]  If there are no "input" seconds present, then there are no "return" seconds present.
;
Func _TimeRound($sTime, $iRoundedInMins = 15)
    Local $sPreDateTime = "2021/01/01 ", $iDecimalplaces = Int(Log(60 * $iRoundedInMins) / Log(10)), $iFactor = (60 * $iRoundedInMins) / (10 ^ $iDecimalplaces)
    Local $sHrZero = StringRegExpReplace($sTime, "(?<=\:)(.+)(?=$)", "00:00") ; Create Hour:00:00, where 'Hour' is the same hour as in $sTime.
    Local $bSecsPresent = StringRegExp($sTime, "\d+:\d+:\d+$") ; If secs are present, then $bSecsPresent is positive (True).
    Local $sDateTime = _DateAdd('s', Round(_DateDiff('s', $sPreDateTime & $sHrZero, $sPreDateTime & $sTime) / $iFactor, -$iDecimalplaces) * $iFactor, $sPreDateTime & $sHrZero)  ; Nearest 900secs (15mins).
    Return StringRegExpReplace($sDateTime, "^\H+\h" & ($bSecsPresent ? "" : "|\:\d+$"), "")
EndFunc   ;==>_TimeRound

#cs ; Returns:-
_TimeRound("12:07")   equals      12:00  ; Note: There are no 'return' seconds present.
_TimeRound("12:8")    equals      12:15
...
_TimeRound("13:07:22")   equals   13:00:00  _TimeRound("13:07:22", 15/60)   equals   13:07:15
_TimeRound("13:07:23")   equals   13:00:00  _TimeRound("13:07:23", 15/60)   equals   13:07:30 <--- Note: Time increments to 30sec because time's seconds > 22.5secs (15+15/2) or (30-15/2)
_TimeRound("13:07:24")   equals   13:00:00  _TimeRound("13:07:24", 15/60)   equals   13:07:30
_TimeRound("13:07:25")   equals   13:00:00  _TimeRound("13:07:25", 15/60)   equals   13:07:30
_TimeRound("13:07:26")   equals   13:00:00  _TimeRound("13:07:26", 15/60)   equals   13:07:30
_TimeRound("13:07:27")   equals   13:00:00  _TimeRound("13:07:27", 15/60)   equals   13:07:30
_TimeRound("13:07:28")   equals   13:00:00  _TimeRound("13:07:28", 15/60)   equals   13:07:30
_TimeRound("13:07:29")   equals   13:00:00  _TimeRound("13:07:29", 15/60)   equals   13:07:30
_TimeRound("13:07:30")   equals   13:15:00  _TimeRound("13:07:30", 15/60)   equals   13:07:30 <--- Note: Time increments to 15min 00sec because time's min & sec equals 7.5min (15/2)
_TimeRound("13:07:31")   equals   13:15:00  _TimeRound("13:07:31", 15/60)   equals   13:07:30
...
#ce

 

Link to post
Share on other sites
  • Moderators
Posted (edited)

zuladabef,

Here is a script that works for both key edit and UpDown:

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <Date.au3>
#include <Misc.au3>

Local $hDLL = DllOpen("user32.dll")

Global $fChange = False, $fMouse = False

; Get current time
    $sTime = _NowTime(4)
    $iHour = Int(StringLeft($sTime, 2))
    $iMins = Int(StringRight($sTime, 2))
    ; Set to nearest quarter
    Switch $iMins
        Case 01 To 07
            $iMins = 0
        Case 08 To 22
            $iMins = 15
        Case 23 To 37
            $iMins = 30
        Case 38 To 52
            $iMins = 45
        Case 53 To 59
            $iMins = 0
            $iHour += 1
            If $iHour = 25 Then
                $iHour = 0
            EndIf
    EndSwitch

$hGUI = GUICreate("Test", 200, 200, 800, 200)

$cDate = GUICtrlCreateDate("", 20, 20, 150, 20, $DTS_TIMEFORMAT)
GUICtrlSendMsg($cDate, $DTM_SETFORMATW, 0, "HH:mm")
GUICtrlSetData($cDate, _NowCalcDate() & StringFormat(" %02i:%02i:00", $iHour, $iMins))

GUISetState(@SW_SHOW)

GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY")

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            DllClose($hDLL)
            ExitLoop
    EndSwitch

    If $fChange Then

        ; In case we need to alter the hour too
        $iHourChange = 0
        ; Read minutes
        $iMins = Int(StringRight(GUICtrlRead($cDate), 2))
        If $fMouse Then
            $fMouse = False
            ; Only need to look for the time +- 1 of the quarters
            Switch $iMins
                Case 1
                    $iMins = 15
                Case 14
                    $iMins = 00
                Case 16
                    $iMins = 30
                Case 29
                    $iMins = 15
                Case 31
                    $iMins = 45
                Case 44
                    $iMins = 30
                Case 46
                    $iMins = 00
                    $iHourChange = +1
                Case 59
                    $iMins = 45
                    $iHourChange = -1
               EndSwitch
        Else
            ; Set to nearest quarter
            Switch $iMins
                Case 01 To 07
                    $iMins = 0
                Case 08 To 22
                    $iMins = 15
                Case 23 To 37
                    $iMins = 30
                Case 38 To 52
                    $iMins = 45
                Case 53 To 59
                    $iMins = 0
                    $iHourChange = +1
            EndSwitch
        EndIf
        $fChange = False
        ; Read hour
        $iAdjustedHour = Int(StringLeft(GUICtrlRead($cDate), 2)) + $iHourChange
        If $iAdjustedHour = 25 Then
            $iAdjustedHour = 0
        EndIf
        If $iAdjustedHour = -1 Then
            $iAdjustedHour = 23
        EndIf
        ; Set new time
        $sDate = _NowCalcDate() & StringFormat(" %02i:%02i:00", $iAdjustedHour, $iMins)
        GUICtrlSetData($cDate, $sDate)
    EndIf
WEnd


Func _WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam

    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)

    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")

    If $iIDFrom = $cDate And $iCode = $DTN_DATETIMECHANGE Then
        ; Change message
        $fChange = True
        ; Should get an almost immediate mouse down
        $iTimer = TimerInit()
        Do
            If _IsPressed("01", $hDLL) Then
                $fMouse = True
                ExitLoop
            EndIf
        Until TimerDiff($iTimer) > 10
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>_WM_NOTIFY

M23

Edited by Melba23
Found a couple of edge cases!

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...