This is the new home of the egghelp.org community forum.
All data has been migrated (including user logins/passwords) to a new phpBB version.


For more information, see this announcement post. Click the X in the top right-corner of this box to dismiss this message.

Find date of second thursday of month

Help for those learning Tcl or writing their own scripts.
J
Jagg
Halfop
Posts: 53
Joined: Sat Jan 24, 2004 11:32 am

Find date of second thursday of month

Post by Jagg »

Hi,

which is the best/easiest way to find the date of the second thursday of a month?

My problem is... I have to cut a year in 4 "ranges"...

Year start until 2nd thursday of march is the first range for example

From 2nd thursday in march until 2nd thursday in june would be the 2nd range i need.

From 2nd thursday in june until 2nd thursday in september would be the 3rd range.

And from 2nd thursday in september until end of year would be the last/4rd range I need.
User avatar
arfer
Master
Posts: 436
Joined: Fri Nov 26, 2004 8:45 pm
Location: Manchester, UK

Post by arfer »

You should be able to adapt the following code. It consists of a proc to find a date given the day name, the month name, the year and the number of such days you require in the month. A PUB bind is provided for testing.

Example to find the 3rd Friday in December 2009 :-
!finddate friday december 2009 3

Note that this code will not work reliably in Windows (Windrop bot). It relies on an error being generated for a false date.

[clock scan 31-February-2011] will correctly yield an error on nix, since no such date exists, but on my windrop bot it returned a time value for 3rd March 2011. ie. the extra days after the end of February rolled over into March.

Code: Select all

set vFinddateVersion 11.03.03.00.35

bind PUB - !finddate pPubFinddate

proc pPubFinddate {nick uhost hand chan text} {
    set vars [split $text]
    if {[llength $vars] == 4} {
        set day [lindex $vars 0]; set month [lindex $vars 1]; set year [lindex $vars 2]; set number [lindex $vars 3]
        switch -- [set date [pParseFinddate $day $month $year $number]] {
            e1 {putserv "PRIVMSG $chan :invalid or misspelt full day name"}
            e2 {putserv "PRIVMSG $chan :invalid or misspelt full month name"}
            e3 {putserv "PRIVMSG $chan :year value was not an integer"}
            e4 {putserv "PRIVMSG $chan :year value was not the 4 digits expected"}
            e5 {putserv "PRIVMSG $chan :year value was outside the range 1971 through 2037"}
            e6 {putserv "PRIVMSG $chan :number value was not an integer"}
            e7 {putserv "PRIVMSG $chan :number value was outside the range 1 through 5"}
            e8 {putserv "PRIVMSG $chan :cannot find $number [string totitle ${day}'s] in [string totitle $month] $year"}
            default {putserv "PRIVMSG $chan :$date"}
        }
    } else {putserv "PRIVMSG $chan :correct syntax is !finddate <day> <month> <year> <number>"}
    return 0
}

proc pParseFinddate {day month year number} {
    set dayname [string tolower $day]
    set monthname [string tolower $month]
    if {[lsearch -exact {sunday monday tuesday wednesday thursday friday saturday} $dayname] == -1} {return e1}
    if {[lsearch -exact {january february march april may june july august september october november december} $monthname] == -1} {return e2}
    if {![string is integer -strict $year]} {return e3}
    if {[string length $year] != 4} {return e4}
    if {($year < 1971) || ($year > 2037)} {return e5}
    if {![string is integer -strict $number]} {return e6}
    if {($number < 1) || ($number > 5)} {return e7}
    set target 1
    for {set loop 1} {$loop <= 32} {incr loop} {
        set date "[format %02i $loop]-[string totitle $monthname]-$year"
        if {[catch {set datevalue [clock scan $date -format "%d-%B-%Y"]}]} {return e8}
        if {[string equal -nocase [clock format $datevalue -format %A] $day]} {
            if {[string equal $target $number]} {
                return [clock format $datevalue -format {%A %d %B %Y}]
            } else {incr target}
        }
    }
    return 0
}

putlog "finddate.tcl version $vFinddateVersion loaded"

# eof
*** EDIT ***
Includes modification suggested by Speechless below, to overcome Tcl 8.5 wrapping extra days from an invalid date
Last edited by arfer on Mon Mar 07, 2011 2:05 pm, edited 1 time in total.
I must have had nothing to do
J
Jagg
Halfop
Posts: 53
Joined: Sat Jan 24, 2004 11:32 am

Post by Jagg »

Thank you very much!!! :!:
User avatar
caesar
Mint Rubber
Posts: 3776
Joined: Sun Oct 14, 2001 8:00 pm
Location: Mint Factory

Post by caesar »

@arfer : the switch supports multiple values in the same case:

Code: Select all

switch $number {
  1 - 3 {
    # something
  }
  2 - 4 {
    # something else
  }
}
Once the game is over, the king and the pawn go back in the same box.
User avatar
arfer
Master
Posts: 436
Joined: Fri Nov 26, 2004 8:45 pm
Location: Manchester, UK

Post by arfer »

Yes I'm aware caesar, but that's only any use if the code for two or more switch values require the same code. All the values in the script above have different code.

I wouldn't mind some explanation of why my Windrop bot rolls extra days over into the next month rather than returning an invalid date. Seems absurd.
I must have had nothing to do
User avatar
caesar
Mint Rubber
Posts: 3776
Joined: Sun Oct 14, 2001 8:00 pm
Location: Mint Factory

Post by caesar »

Ahh... just ignore my previous post, I misread something. :)

Don't know, maybe is something Windrop related. :roll:
Once the game is over, the king and the pawn go back in the same box.
User avatar
speechles
Revered One
Posts: 1398
Joined: Sat Aug 26, 2006 10:19 pm
Location: emerald triangle, california (coastal redwoods)

Post by speechles »

arfer wrote:Yes I'm aware caesar, but that's only any use if the code for two or more switch values require the same code. All the values in the script above have different code.

I wouldn't mind some explanation of why my Windrop bot rolls extra days over into the next month rather than returning an invalid date. Seems absurd.
tcl 8.4 clock wrote:.tcl [clock scan 31-February-2011]
Tcl error: unable to convert date-time string "31-February-2011"
Indeed, welcome to the new (improved??!) clock within tcl 8.5. Give it bogus dates, it will return bogus values. Give it the 35th of a month, it will wrap 4 or 5 days into the next month (those with 30/31 days). This is due to tcl8.5 requiring the -format command to implicitly tell it the format you are giving it when using scan. It will no longer allow 'free-form" guesses like tcl8.4 clock did. This is why you see it wrapping into March.

Code: Select all

#The issue
if {[catch {set datevalue [clock scan $date]}]} {return e8}
You use [clock scan] but you are not using -format within it.. This causes your problem..

Code: Select all

#The solution
if {[catch {set datevalue [clock scan $date -format "%d-%B-%Y"]}]} {return e8}
-format format
Specifies the desired output format for clock format or the expected input format for clock scan. The format string consists of any number of characters other than the per-cent sign (“%”) interspersed with any number of format groups, which are two-character sequences beginning with the per-cent sign. The permissible format groups, and their interpretation, are described under FORMAT GROUPS.
User avatar
arfer
Master
Posts: 436
Joined: Fri Nov 26, 2004 8:45 pm
Location: Manchester, UK

Post by arfer »

Thanks speechless, that does explain things. I have modified the script in my original post according to your recommendations. Hopefully Jagg is still following the thread he created.

One possible problem though, I'm assuming the code no longer works on Tcl 8.4?
I must have had nothing to do
User avatar
speechles
Revered One
Posts: 1398
Joined: Sat Aug 26, 2006 10:19 pm
Location: emerald triangle, california (coastal redwoods)

Post by speechles »

arfer wrote:Thanks speechless, that does explain things. I have modified the script in my original post according to your recommendations. Hopefully Jagg is still following the thread he created.

One possible problem though, I'm assuming the code no longer works on Tcl 8.4?
It worked on tcl8.4 unaltered the way you had it. It will trigger error condition #8 (e8) properly and pass it.

But yes, adding the -format switch to [clock scan] will only work on tcl8.5. To make it work for both, you would have to check $tcl_version and use your original method for 8.4, or the -format within the [clock scan] for 8.5. You are indeed correct. ;)
User avatar
arfer
Master
Posts: 436
Joined: Fri Nov 26, 2004 8:45 pm
Location: Manchester, UK

Post by arfer »

Still not functioning correctly on my Windrop bot (1.6.19) with Tcl 8.5

[19:07] <@arfer> !finddate monday february 2010 5
[19:07] <osmosis> Monday 01 March 2010
[19:08] <@arfer> !finddate saturday february 2010 5
[19:08] <osmosis> 0

[19:22] <arfer> .tcl [clock scan 31-February-2010 -format "%d-%B-%Y"]
[19:22] <osmosis> Tcl error: invalid command name "1267574400"

I'm beginning to think I need to construct a different method/logic, unless somebody can see the issue.
I must have had nothing to do
User avatar
arfer
Master
Posts: 436
Joined: Fri Nov 26, 2004 8:45 pm
Location: Manchester, UK

Post by arfer »

Fixed :-

Code: Select all

set vFinddateVersion 11.03.07.21.48

bind PUB - !finddate pPubFinddate

proc pPubFinddate {nick uhost hand chan text} {
    set vars [split $text]
    if {[llength $vars] == 4} {
        set day [lindex $vars 0]; set month [lindex $vars 1]; set year [lindex $vars 2]; set number [lindex $vars 3]
        switch -- [set date [pParseFinddate $day $month $year $number]] {
            e1 {putserv "PRIVMSG $chan :invalid or misspelt full day name"}
            e2 {putserv "PRIVMSG $chan :invalid or misspelt full month name"}
            e3 {putserv "PRIVMSG $chan :year value was not an integer"}
            e4 {putserv "PRIVMSG $chan :year value was not the 4 digits expected"}
            e5 {putserv "PRIVMSG $chan :year value was outside the range 1971 through 2037"}
            e6 {putserv "PRIVMSG $chan :number value was not an integer"}
            e7 {putserv "PRIVMSG $chan :number value was outside the range 1 through 5"}
            e8 {putserv "PRIVMSG $chan :cannot find $number [string totitle ${day}'s] in [string totitle $month] $year"}
            default {putserv "PRIVMSG $chan :$date"}
        }
    } else {putserv "PRIVMSG $chan :correct syntax is !finddate <day> <month> <year> <number>"}
    return 0
}

proc pParseFinddate {day month year number} {
    set dayname [string tolower $day]
    set monthname [string tolower $month]
    if {[lsearch -exact {sunday monday tuesday wednesday thursday friday saturday} $dayname] == -1} {return e1}
    if {[lsearch -exact {january february march april may june july august september october november december} $monthname] == -1} {return e2}
    if {![string is integer -strict $year]} {return e3}
    if {[string length $year] != 4} {return e4}
    if {($year < 1971) || ($year > 2037)} {return e5}
    if {![string is integer -strict $number]} {return e6}
    if {($number < 1) || ($number > 5)} {return e7}
    set target 1
    for {set loop 1} {$loop <= 32} {incr loop} {
        set date "[format %02i $loop]-[string totitle $monthname]-$year"
        if {[catch {set datevalue [clock scan $date]}]} {return e8}
        if {![string equal -nocase [clock format $datevalue -format %B] $monthname]} {return e8}
        if {[string equal -nocase [clock format $datevalue -format %A] $day]} {
            if {[string equal $target $number]} {
                return [clock format $datevalue -format {%A %d %B %Y}]
            } else {incr target}
        }
    }
    return 0
}

putlog "finddate.tcl version $vFinddateVersion loaded"

# eof
[21:47] <@arfer> !finddate monday december 2010 5
[21:47] <osmosis> cannot find 5 Monday's in December 2010
[21:47] <@arfer> !finddate tuesday december 2010 5
[21:47] <osmosis> cannot find 5 Tuesday's in December 2010
[21:47] <@arfer> !finddate wednesday december 2010 5
[21:47] <osmosis> Wednesday 29 December 2010
I must have had nothing to do
J
Jagg
Halfop
Posts: 53
Joined: Sat Jan 24, 2004 11:32 am

Post by Jagg »

@arfer ...do your last posted version (above my post here) still work with tcl 8.4 and 8.5 or only with 8.5?
User avatar
arfer
Master
Posts: 436
Joined: Fri Nov 26, 2004 8:45 pm
Location: Manchester, UK

Post by arfer »

This latest 'fixed' version should now work with Eggdrop or Windrop and with Tcl 8.4 or Tcl 8.5
I must have had nothing to do
J
Jagg
Halfop
Posts: 53
Joined: Sat Jan 24, 2004 11:32 am

Post by Jagg »

I have now the problem that my server/eggdrop is in CET time.

so i get this

% clock format [clock scan now] -format "%B"
März
% clock format [clock scan now] -format "%A"
Dienstag

That means I have a problem now... because that clock scan line only works with english month names, doesn't it?

And when i give it the english monthname the next line with e.g. clock format $datevalue -format %B doesn't work anymore because clock format gives me the CET monthname :? (März vs. March and so on... it only works on month which are similar in spelling like august, september,...)
User avatar
caesar
Mint Rubber
Posts: 3776
Joined: Sun Oct 14, 2001 8:00 pm
Location: Mint Factory

Post by caesar »

So what stops you from replacing in this two lines:

Code: Select all

    if {[lsearch -exact {sunday monday tuesday wednesday thursday friday saturday} $dayname] == -1} {return e1}
    if {[lsearch -exact {january february march april may june july august september october november december} $monthname] == -1} {return e2} 
the correct text for day and month?
Last edited by caesar on Tue Mar 08, 2011 6:55 am, edited 3 times in total.
Once the game is over, the king and the pawn go back in the same box.
Post Reply