Browse Source

punk::timeinterval and winlibreoffice fixes

master
Julian Noble 3 weeks ago
parent
commit
c94f4cc0f6
  1. 423
      src/modules/punk/timeinterval-999999.0a1.0.tm
  2. 180
      src/modules/winlibreoffice-999999.0a1.0.tm

423
src/modules/punk/timeinterval-999999.0a1.0.tm

@ -27,18 +27,24 @@
#
namespace eval punk::timeinterval {
proc clock_scan_interval { seconds delta units } {
# clock_scan_interval formats $seconds to a string for processing by clock scan
# then returns new timestamp in seconds
set stamp [clock format $seconds -format "%Y%m%dT%H%M%S"]
if { $delta < 0 } {
append stamp " - " [expr { abs( $delta ) } ] " " $units
} else {
append stamp " + " $delta " " $units
}
return [clock scan $stamp]
}
#The free-form 'clock scan' is deprecated. It worked in 8.4 to 8.6/8.7 (and earlier?) - but doesn't work in tcl9
#proc clock_scan_interval { seconds delta units } {
# # clock_scan_interval formats $seconds to a string for processing by clock scan
# # then returns new timestamp in seconds
# set stamp [clock format $seconds -format "%Y%m%dT%H%M%S"]
# if { $delta < 0 } {
# append stamp " - " [expr { abs( $delta ) } ] " " $units
# } else {
# append stamp " + " $delta " " $units
# }
# return [clock scan $stamp]
#}
#proc clock_scan_interval { seconds delta units } {
# #8.6+
# clock add $seconds $delta $units
#}
namespace export difference
#wrap in dict
@ -46,21 +52,36 @@ namespace eval punk::timeinterval {
lassign [interval_ymdhs $s1 $s2] Y M D h m s
return [dict create years $Y months $M days $D hours $h minutes $m seconds $s]
}
proc interval_ymdhs { s1 s2 } {
# interval_ymdhs calculates the interval of time between
# the earliest date and the last date
# by starting to count at the earliest date.
lappend PUNKARGS [list {
@id -id "::punk::timeinterval::interval_ymdhs"
@cmd -name "punk::timeinterval::interval_ymdhs" -help\
"interval_ymdhs calculates the interval of time between
the earliest date and the last date
by starting to count at the earliest date."
@opts
-maxunit -default years -choices {years months days hours minutes seconds}
-timezone -default ""
@values -min 2 -max 2
s1
s2
}]
proc interval_ymdhs {args} {
set argd [punk::args::parse $args withid ::punk::timeinterval::interval_ymdhs]
lassign [dict values $argd] leaders opts values received
set maxunit [dict get $opts -maxunit]
set timezone [dict get $opts -timezone]
set s1 [dict get $values s1]
set s2 [dict get $values s2]
# This proc has audit features. It will automatically
# attempt to correct and report any discrepancies it finds.
# if s1 and s2 aren't in seconds, convert to seconds.
if { ![string is integer -strict $s1] } {
set s1 [clock scan $s1]
set s1 [clock scan $s1 -timezone $timezone]
}
if { ![string is integer -strict $s2] } {
set s2 [clock scan $s2]
set s2 [clock scan $s2 -timezone $timezone]
}
# postgreSQL intervals determine month length based on earliest date in interval calculations.
@ -68,7 +89,7 @@ namespace eval punk::timeinterval {
set sn_list [lsort -integer [list $s1 $s2]]
set s1 [lindex $sn_list 0]
set s2 [lindex $sn_list 1]
# Arithmetic is done from most significant to least significant
# The interval is spanned in largest units first.
# A new position s1_pN is calculated for the Nth move along the interval.
@ -77,64 +98,82 @@ namespace eval punk::timeinterval {
# Calculate years from s1_p0 to s2
set y_count 0
set s1_p0 $s1
set s2_y_check $s1_p0
while { $s2_y_check <= $s2 } {
set s1_p1 $s2_y_check
set y $y_count
incr y_count
set s2_y_check [clock_scan_interval $s1_p0 $y_count years]
}
# interval s1_p0 to s1_p1 counted in y years
if {$maxunit eq "years"} {
set s2_y_check $s1_p0
while { $s2_y_check <= $s2 } {
set s1_p1 $s2_y_check
set y $y_count
incr y_count
set s2_y_check [clock add $s1_p0 $y_count years -timezone $timezone]
}
# interval s1_p0 to s1_p1 counted in y years
# is the base offset incremented one too much?
set s2_y_check [clock_scan_interval $s1 $y years]
if { $s2_y_check > $s2 } {
set y [expr { $y - 1 } ]
set s2_y_check [clock_scan_interval $s1 $y years]
}
# increment s1 (s1_p0) forward y years to s1_p1
if { $y == 0 } {
set s1_p1 $s1
# is the base offset incremented one too much?
set s2_y_check [clock add $s1 $y years -timezone $timezone]
if { $s2_y_check > $s2 } {
set y [expr { $y - 1 } ]
set s2_y_check [clock add $s1 $y years -timezone $timezone]
}
# increment s1 (s1_p0) forward y years to s1_p1
if { $y == 0 } {
set s1_p1 $s1
} else {
set s1_p1 [clock add $s1 $y years -timezone $timezone]
}
} else {
set s1_p1 [clock_scan_interval $s1 $y years]
set y 0
set s1_p1 $s1
}
# interval s1 to s1_p1 counted in y years
# Calculate months from s1_p1 to s2
set m_count 0
set s2_m_check $s1_p1
while { $s2_m_check <= $s2 } {
set s1_p2 $s2_m_check
set m $m_count
incr m_count
set s2_m_check [clock_scan_interval $s1_p1 $m_count months]
set s1_p2 $s1_p1 ;#?
set m 0
if {$maxunit in {years months}} {
while { $s2_m_check <= $s2 } {
set s1_p2 $s2_m_check
set m $m_count
incr m_count
set s2_m_check [clock add $s1_p1 $m_count months -timezone $timezone]
}
}
# interval s1_p1 to s1_p2 counted in m months
# Calculate interval s1_p2 to s2 in days
# day_in_sec [expr { 60 * 60 * 24 } ]
# 86400
# Since length of month is not relative, use math.
# Clip any fractional part.
set d [expr { int( ( $s2 - $s1_p2 ) / 86400. ) } ]
# Ideally, this should always be true, but daylight savings..
# so, go backward one day and make hourly steps for last day.
if { $d > 0 } {
incr d -1
set d 0
set s1_p3 $s1_p2
if {$maxunit in {years months days}} {
# Calculate interval s1_p2 to s2 in days
# day_in_sec [expr { 60 * 60 * 24 } ]
# 86400
# Since length of month is not relative, use math.
# Clip any fractional part.
set d [expr { int( ( $s2 - $s1_p2 ) / 86400. ) } ]
# Ideally, this should always be true, but daylight savings..
# so, go backward one day and make hourly steps for last day.
if { $d > 0 } {
incr d -1
}
# Move interval from s1_p2 to s1_p3
set s1_p3 [clock add $s1_p2 $d days -timezone $timezone]
}
# Move interval from s1_p2 to s1_p3
set s1_p3 [clock_scan_interval $s1_p2 $d days]
# s1_p3 is less than a day from s2
# Calculate interval s1_p3 to s2 in hours
# hour_in_sec [expr { 60 * 60 } ]
# 3600
set h [expr { int( ( $s2 - $s1_p3 ) / 3600. ) } ]
# Move interval from s1_p3 to s1_p4
set s1_p4 [clock_scan_interval $s1_p3 $h hours]
# s1_p4 is less than an hour from s2
set h 0
set s1_p4 $s1_p3
if {$maxunit in {years months days hours}} {
# Calculate interval s1_p3 to s2 in hours
# hour_in_sec [expr { 60 * 60 } ]
# 3600
set h [expr { int( ( $s2 - $s1_p3 ) / 3600. ) } ]
# Move interval from s1_p3 to s1_p4
set s1_p4 [clock add $s1_p3 $h hours -timezone $timezone]
# s1_p4 is less than an hour from s2
}
# Sometimes h = 24, yet is already included as a day!
@ -143,81 +182,97 @@ namespace eval punk::timeinterval {
# from Age() example in PostgreSQL documentation:
# http://www.postgresql.org/docs/9.1/static/functions-datetime.html
# psql test=# select age(timestamp '2001-04-10', timestamp '1957-06-13');
# age
# age
# -------------------------
# 43 years 9 mons 27 days
# (1 row)
# According to LibreCalc, the difference is 16007 days
#puts "s2=s1+16007days? [clock format [clock_scan_interval $s1 16007 days] -format %Y%m%dT%H%M%S]"
# ^ this calc is consistent with 16007 days
#puts "s2=s1+16007days? [clock format [clock add $s1 16007 days] -format %Y%m%dT%H%M%S]"
# ^ this calc is consistent with 16007 days
# So, let's ignore the Postgresql irregularity for now.
# Here's more background:
# http://www.postgresql.org/message-id/5A86CA18-593F-4517-BB83-995115A6A402@morth.org
# http://www.postgresql.org/message-id/200707060844.l668i89w097496@wwwmaster.postgresql.org
# So, Postgres had a bug..
# Sanity check: if over 24 or 48 hours, push it up to a day unit
set h_in_days [expr { int( $h / 24. ) } ]
if { $h >= 1 } {
# adjust hours to less than a day
set h [expr { $h - ( 24 * $h_in_days ) } ]
incr d $h_in_days
set h_correction_p 1
} else {
set h_correction_p 0
if {$maxunit in {years months days}} {
# Sanity check: if over 24 or 48 hours, push it up to a day unit
set h_in_days [expr { int( $h / 24. ) } ]
if { $h >= 1 } {
# adjust hours to less than a day
set h [expr { $h - ( 24 * $h_in_days ) } ]
incr d $h_in_days
set h_correction_p 1
} else {
set h_correction_p 0
}
}
# Calculate interval s1_p4 to s2 in minutes
# minute_in_sec [expr { 60 } ]
# 60
set mm [expr { int( ( $s2 - $s1_p4 ) / 60. ) } ]
# Move interval from s1_p4 to s1_p5
set s1_p5 [clock_scan_interval $s1_p4 $mm minutes]
# Sanity check: if 60 minutes, push it up to an hour unit
if { $mm >= 60 } {
# adjust 60 minutes to 1 hour
# puts "interval_ymdhs: debug info mm - 60, h + 1"
set mm [expr { $mm - 60 } ]
incr h
set mm_correction_p 1
} else {
set mm_correction_p 0
set mm 0
set s1_p5 $s1_p4
if {$maxunit in {years months days hours minutes}} {
# Calculate interval s1_p4 to s2 in minutes
# minute_in_sec [expr { 60 } ]
# 60
set mm [expr { int( ( $s2 - $s1_p4 ) / 60. ) } ]
# Move interval from s1_p4 to s1_p5
set s1_p5 [clock add $s1_p4 $mm minutes -timezone $timezone]
}
if {$maxunit in {years months days hours}} {
# Sanity check: if 60 minutes, push it up to an hour unit
if { $mm >= 60 } {
# adjust 60 minutes to 1 hour
# puts "interval_ymdhs: debug info mm - 60, h + 1"
set mm [expr { $mm - 60 } ]
incr h
set mm_correction_p 1
} else {
set mm_correction_p 0
}
}
# Calculate interval s1_p5 to s2 in seconds
set s [expr { int( $s2 - $s1_p5 ) } ]
# Sanity check: if 60 seconds, push it up to one minute unit
if { $s >= 60 } {
# adjust 60 minutes to 1 hour
set s [expr { $s - 60 } ]
incr mm
set s_correction_p 1
} else {
set s_correction_p 0
if {$maxunit in {years months days hours minutes}} {
# Sanity check: if 60 seconds, push it up to one minute unit
if { $s >= 60 } {
# adjust 60 minutes to 1 hour
set s [expr { $s - 60 } ]
incr mm
set s_correction_p 1
} else {
set s_correction_p 0
}
}
set return_list [list $y $m $d $h $mm $s]
# test results by adding difference to s1 to get s2:
set i 0
set s1_test [clock format $s1 -format "%Y%m%dT%H%M%S"]
#set s1_test [clock format $s1 -format "%Y%m%dT%H%M%S"]
set signs_inconsistent_p 0
set diffterms [list]
foreach unit {years months days hours minutes seconds} {
set t_term [lindex $return_list $i]
if { $t_term != 0 } {
if { $t_term > 0 } {
append s1_test " + $t_term $unit"
#append s1_test " +$t_term $unit"
lappend diffterms +$t_term $unit
} else {
append s1_test " - [expr { abs( $t_term ) } ] $unit"
#append s1_test " -[expr { abs( $t_term ) } ] $unit"
lappend diffterms -[expr { abs( $t_term ) }] $unit
set signs_inconsistent_p 1
}
}
incr i
}
set s2_test [clock scan $s1_test]
#set s2_test [clock scan $s1_test]
set s2_test [clock add $s1 {*}$diffterms -timezone $timezone]
# puts "test s2 '$s2_test' from: '$s1_test'"
set counter 0
while { $s2 ne $s2_test && $counter < 30 } {
@ -257,29 +312,33 @@ namespace eval punk::timeinterval {
puts "interval_ymdhs: debug, audit adjustment. increasing 1 second to $s"
}
}
set return_list [list $y $m $d $h $mm $s]
# set return_list [list [expr { abs($y) } ] [expr { abs($m) } ] [expr { abs($d) } ] [expr { abs($h) } ] [expr { abs($mm) } ] [expr { abs($s) } ]]
# test results by adding difference to s1 to get s2:
set i 0
set s1_test [clock format $s1 -format "%Y%m%dT%H%M%S"]
#set s1_test [clock format $s1 -format "%Y%m%dT%H%M%S"]
set diffterms [list]
foreach unit {years months days hours minutes seconds} {
set t_term [lindex $return_list $i]
if { $t_term != 0 } {
if { $t_term > 0 } {
append s1_test " + $t_term $unit"
#append s1_test " +$t_term $unit"
lappend diffterms +$t_term $unit
} else {
append s1_test " - [expr { abs( $t_term ) } ] $unit"
#append s1_test " -[expr { abs( $t_term ) } ] $unit"
lappend diffterms -[expr { abs( $t_term ) }] $unit
}
}
incr i
}
set s2_test [clock scan $s1_test]
#set s2_test [clock scan $s1_test]
set s2_test [clock add $s1 {*}$diffterms -timezone $timezone]
incr counter
}
if { ( $counter > 0 || $signs_inconsistent_p ) && ( $h_correction_p || $mm_correction_p || $s_correction_p ) } {
# puts "interval_ymdhs: Corrections in the main calculation were applied: h ${h_correction_p}, mm ${mm_correction_p}, s ${s_correction_p}"
# puts "interval_ymdhs: Corrections in the main calculation were applied: h ${h_correction_p}, mm ${mm_correction_p}, s ${s_correction_p}"
}
if { $signs_inconsistent_p } {
puts "\ninterval_ymdhs: signs inconsistent y $y m $m d $d h $h mm $mm s $s"
@ -328,7 +387,7 @@ namespace eval punk::timeinterval {
set sn_list [lsort -decreasing -integer [list $s1 $s2]]
set s1 [lindex $sn_list 0]
set s2 [lindex $sn_list 1]
# Arithmetic is done from most significant to least significant
# The interval is spanned in largest units first.
# A new position s1_pN is calculated for the Nth move along the interval.
@ -342,7 +401,7 @@ namespace eval punk::timeinterval {
set s1_p1 $s2_y_check
set y $y_count
incr y_count -1
set s2_y_check [clock_scan_interval $s1_p0 $y_count years]
set s2_y_check [clock add $s1_p0 $y_count years]
}
# interval s1_p0 to s1_p1 counted in y years
@ -354,7 +413,7 @@ namespace eval punk::timeinterval {
set s1_p2 $s2_m_check
set m $m_count
incr m_count -1
set s2_m_check [clock_scan_interval $s1_p1 $m_count months]
set s2_m_check [clock add $s1_p1 $m_count months]
}
# interval s1_p1 to s1_p2 counted in m months
@ -371,7 +430,7 @@ namespace eval punk::timeinterval {
}
# Move interval from s1_p2 to s1_p3
set s1_p3 [clock_scan_interval $s1_p2 $d days]
set s1_p3 [clock add $s1_p2 $d days]
# s1_p3 is less than a day from s2
@ -380,7 +439,7 @@ namespace eval punk::timeinterval {
# 3600
set h [expr { int( ceil( ( $s2 - $s1_p3 ) / 3600. ) ) } ]
# Move interval from s1_p3 to s1_p4
set s1_p4 [clock_scan_interval $s1_p3 $h hours]
set s1_p4 [clock add $s1_p3 $h hours]
# s1_p4 is less than an hour from s2
# Sanity check: if over 24 or 48 hours, push it up to a day unit
@ -399,7 +458,7 @@ namespace eval punk::timeinterval {
# 60
set mm [expr { int( ceil( ( $s2 - $s1_p4 ) / 60. ) ) } ]
# Move interval from s1_p4 to s1_p5
set s1_p5 [clock_scan_interval $s1_p4 $mm minutes]
set s1_p5 [clock add $s1_p4 $mm minutes]
# Sanity check: if 60 minutes, push it up to an hour unit
if { $mm <= -60 } {
@ -430,21 +489,25 @@ namespace eval punk::timeinterval {
# test results by adding difference to s1 to get s2:
set i 0
set s1_test [clock format $s1 -format "%Y%m%dT%H%M%S"]
#set s1_test [clock format $s1 -format "%Y%m%dT%H%M%S"]
set signs_inconsistent_p 0
set diffterms [list]
foreach unit {years months days hours minutes seconds} {
set t_term [lindex $return_list $i]
if { $t_term != 0 } {
if { $t_term > 0 } {
append s1_test " + $t_term $unit"
#append s1_test " + $t_term $unit"
lappend diffterms +$t_term $unit
set signs_inconsistent_p 1
} else {
append s1_test " - [expr { abs( $t_term ) } ] $unit"
#append s1_test " - [expr { abs( $t_term ) } ] $unit"
lappend diffterms -[expr { abs( $t_term ) } ] $unit
}
}
incr i
}
set s2_test [clock scan $s1_test]
#set s2_test [clock scan $s1_test]
set s2_test [clock add $s1 {*}$diffterms]
set counter 0
while { $s2 ne $s2_test && $counter < 3 } {
@ -484,29 +547,33 @@ namespace eval punk::timeinterval {
puts "interval_remains_ymdhs: debug, audit adjustment. increasing 1 second to $s"
}
}
set return_list [list $y $m $d $h $mm $s]
# set return_list [list [expr { abs($y) } ] [expr { abs($m) } ] [expr { abs($d) } ] [expr { abs($h) } ] [expr { abs($mm) } ] [expr { abs($s) } ]]
# test results by adding difference to s1 to get s2:
set i 0
set s1_test [clock format $s1 -format "%Y%m%dT%H%M%S"]
#set s1_test [clock format $s1 -format "%Y%m%dT%H%M%S"]
set diffterms [list]
foreach unit {years months days hours minutes seconds} {
set t_term [lindex $return_list $i]
if { $t_term != 0 } {
if { $t_term > 0 } {
append s1_test " + $t_term $unit"
#append s1_test " + $t_term $unit"
lappend diffterms +$t_term $unit
} else {
append s1_test " - [expr { abs( $t_term ) } ] $unit"
#append s1_test " - [expr { abs( $t_term ) } ] $unit"
lappend diffterms -[expr { abs( $t_term ) } ] $unit
}
}
incr i
}
set s2_test [clock scan $s1_test]
#set s2_test [clock scan $s1_test]
set s2_test [clock add $s1 {*}$diffterms]
incr counter
}
if { ( $counter > 0 || $signs_inconsistent_p ) && ( $h_correction_p || $mm_correction_p || $s_correction_p ) } {
# puts "interval_remains_ymdhs: Corrections in the main calculation were applied: h ${h_correction_p}, mm ${mm_correction_p}, s ${s_correction_p}"
# puts "interval_remains_ymdhs: Corrections in the main calculation were applied: h ${h_correction_p}, mm ${mm_correction_p}, s ${s_correction_p}"
}
if { $signs_inconsistent_p } {
puts "\ninterval_remains_ymdhs: signs inconsistent y $y m $m d $d h $h mm $mm s $s"
@ -526,7 +593,7 @@ namespace eval punk::timeinterval {
proc interval_remains_ymdhs_w_units { t1 t2 } {
# interval_remains_ymdhs_w_units
# returns interval_remains_ymdhs values with units
set v_list [interval_ymdhs $t2 $t1]
set v_list [interval_remains_ymdhs $t2 $t1]
set i 0
set a ""
foreach f {years months days hours minutes seconds} {
@ -543,7 +610,105 @@ namespace eval punk::timeinterval {
# == === === === === === === === === === === === === === ===
# Sample 'about' function with punk::args documentation
# == === === === === === === === === === === === === === ===
tcl::namespace::eval punk::timeinterval {
tcl::namespace::export {[a-zA-Z]*} ;# Convention: export all lowercase
variable PUNKARGS
variable PUNKARGS_aliases
lappend PUNKARGS [list {
@id -id "(package)punk::timeinterval"
@package -name "punk::timeinterval" -help\
"time interval from wiki"
}]
namespace eval argdoc {
#namespace for custom argument documentation
proc package_name {} {
return punk::timeinterval
}
proc about_topics {} {
#info commands results are returned in an arbitrary order (like array keys)
set topic_funs [info commands [namespace current]::get_topic_*]
set about_topics [list]
foreach f $topic_funs {
set tail [namespace tail $f]
lappend about_topics [string range $tail [string length get_topic_] end]
}
#Adjust this function or 'default_topics' if a different order is required
return [lsort $about_topics]
}
proc default_topics {} {return [list Description *]}
# -------------------------------------------------------------
# get_topic_ functions add more to auto-include in about topics
# -------------------------------------------------------------
proc get_topic_Description {} {
punk::args::lib::tstr [string trim {
package punk::timeinterval
basic time interval calculations
} \n]
}
proc get_topic_License {} {
return "X11"
}
proc get_topic_Version {} {
return "$::punk::timeinterval::version"
}
proc get_topic_Contributors {} {
set authors {{various "https://wiki.tcl-lang.org/page/Measuring+time+intervals+%28between+two+timestamps%29+with+months+etc"} {Julian Noble <julian@precisium.com.au>}}
set contributors ""
foreach a $authors {
append contributors $a \n
}
if {[string index $contributors end] eq "\n"} {
set contributors [string range $contributors 0 end-1]
}
return $contributors
}
proc get_topic_notes {} {
punk::args::lib::tstr -return string {
X11 license - is MIT with additional clause regarding use of contributor names.
}
}
# -------------------------------------------------------------
}
# we re-use the argument definition from punk::args::standard_about and override some items
set overrides [dict create]
dict set overrides @id -id "::punk::timeinterval::about"
dict set overrides @cmd -name "punk::timeinterval::about"
dict set overrides @cmd -help [string trim [punk::args::lib::tstr {
About punk::timeinterval
}] \n]
dict set overrides topic -choices [list {*}[punk::timeinterval::argdoc::about_topics] *]
dict set overrides topic -choicerestricted 1
dict set overrides topic -default [punk::timeinterval::argdoc::default_topics] ;#if -default is present 'topic' will always appear in parsed 'values' dict
set newdef [punk::args::resolved_def -antiglobs -package_about_namespace -override $overrides ::punk::args::package::standard_about *]
lappend PUNKARGS [list $newdef]
proc about {args} {
package require punk::args
#standard_about accepts additional choices for topic - but we need to normalize any abbreviations to full topic name before passing on
set argd [punk::args::parse $args withid ::punk::timeinterval::about]
lassign [dict values $argd] _leaders opts values _received
punk::args::package::standard_about -package_about_namespace ::punk::timeinterval::argdoc {*}$opts {*}[dict get $values topic]
}
}
# end of sample 'about' function
# == === === === === === === === === === === === === === ===
# -----------------------------------------------------------------------------
# register namespace(s) to have PUNKARGS,PUNKARGS_aliases variables checked
# -----------------------------------------------------------------------------
# variable PUNKARGS
# variable PUNKARGS_aliases
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
lappend ::punk::args::register::NAMESPACES ::punk::timeinterval
}
@ -553,9 +718,9 @@ namespace eval punk::timeinterval {
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
## Ready
package provide punk::timeinterval [namespace eval punk::timeinterval {
variable version
set version 999999.0a1.0
set version 999999.0a1.0
}]
return

180
src/modules/winlibreoffice-999999.0a1.0.tm

@ -28,15 +28,16 @@ if {"windows" eq $::tcl_platform(platform)} {
puts stderr "Minimal functionality - only some utils may work"
}
} else {
puts stderr "Package requires twapi. No current equivalent on non-windows platform. Try tcluno http://sf.net/projets/tcluno "
puts stderr "Package requires twapi. No current equivalent on non-windows platform. Try tcluno http://sf.net/projets/tcluno"
puts stderr "Minimal functionality - only some utils may work"
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval winlibreoffice {
namespace export from_libre_date to_libre_date
#---
#todo: investigate tcluno package http://sf.net/projects/tcluno
#todo: investigate tcluno package http://sf.net/projects/tcluno
#CPlusPlus - platforms?
#---
#
@ -48,10 +49,10 @@ namespace eval winlibreoffice {
#sometimes a com object may support $obj -print
#see also
# $obj -destroy
# $obj -destroy
# $obj Quit
# $collection -iterate ?options? varname script
variable uno "" ;# service manager object
variable psm "" ;# process service manager
@ -91,7 +92,7 @@ namespace eval winlibreoffice {
return $fpath
}
#
#
proc convertFromUrl {fileuri} {
if {[string match "file:/*" $fileuri]} {
set finfo [uri::split $fileuri]
@ -100,7 +101,7 @@ namespace eval winlibreoffice {
return "//${host}${path}"
} else {
#the leading slash in path indicates a local path and we strip on windows
set p [dict get $finfo path]
set p [dict get $finfo path]
if {[string index $p 0] eq "/"} {
set p [string range $p 1 end]
}
@ -111,12 +112,12 @@ namespace eval winlibreoffice {
#?? review - how are file uris to other hosts handled?
error "convertFromUrl doesn't handle non-local file uris on this platform"
} else {
return [dict get $finfo path]
return [dict get $finfo path]
}
}
}
}
}
# -- --- --- ---
# custom functions
@ -127,7 +128,7 @@ namespace eval winlibreoffice {
#$dt setName odk_officedev_desk
#$dt getName
return $dt
}
}
proc blankdoc {{type scalc}} {
set known_types [list scalc swriter simpress sdraw smath]
@ -139,7 +140,7 @@ namespace eval winlibreoffice {
puts "doc title: [$doc Title]"
#title can be set with [$doc settitle "titletext"]
return $doc
}
}
proc file_open_dialog {{title "pick a libreoffice file"}} {
set filepicker [createUnoService "com.sun.star.ui.dialogs.FilePicker"]
@ -175,7 +176,7 @@ namespace eval winlibreoffice {
$cell setValue $value
}
proc calccell_setPropertyValue {cell propset} {
$cell setPropertyValue {*}$propset
$cell setPropertyValue {*}$propset
#e.g "NumberFormat" 49
# YYYY-MM-DD
@ -192,7 +193,7 @@ namespace eval winlibreoffice {
set dec [punk::lib::hex2dec $rgb]
$cell setPropertyValue "CharColor" [expr {$dec}]
}
#cell charFontName
@ -201,7 +202,7 @@ namespace eval winlibreoffice {
#https://api.libreoffice.org/docs/idl/ref/FontWeight_8idl.html
# values are listed with 6 DPs - but one seems to work
# only setting to normal and bold seem to result in a value (regular & bold) in the format->font style dialog for the cell.
#DONTKNOW 0.0
#DONTKNOW 0.0
#THIN 50.0
#ULTRALIGHT 60.0
#LIGHT 75.0
@ -212,31 +213,132 @@ namespace eval winlibreoffice {
#ULTRABOLD 175.0
#BLACK 200.0
lappend PUNKARGS [list {
@id -id ::winlibreoffice::to_libre_date
@cmd -name winlibreoffice::to_libre_date -help\
"Return an internal Libre Office date/time floating point
number representing the number of days since 1899-12-30.
e.g
% to_libre_date 2025-02-28T060000
45716.25
% to_libre_date 2025-01-01T060101
45658.250706018516
"
@opts
-timezone -default "" -help\
"If unspecified, the timezone will be the
current time zone on the system"
@values -min 1 -max 1
time -type string -help\
"A unix timestamp as output by 'clock seconds'
or a text timestamp such as 2025-01-03T000000
parseable by 'clock scan'"
}]
proc to_libre_date {args} {
package require punk::args
set argd [punk::args::parse $args withid ::winlibreoffice::to_libre_date]
lassign [dict values $argd] leaders opts values received
set tz [dict get $opts -timezone]
set time [dict get $values time]
if {![string is integer -strict $time]} {
set ts [clock scan $time -timezone $tz]
} else {
set ts $time
}
#a hack
#return libreoffice date in days since 1899..
proc date_from_clockseconds_approx {cs} {
variable datebase
set tbase [clock scan $datebase]
set tbase [clock scan $datebase -timezone $tz]
package require punk::timeinterval
set diff [punk::timeinterval::difference $tbase $cs]
set info [punk::timeinterval::interval_ymdhs -maxunit days -timezone $tz $tbase $ts]
lassign $info Y m days h m s
set Y [dict get $diff years]
set M [dict get $diff months]
set D [dict get $diff days]
set yeardays [expr 365.25 * $Y]
set monthdays [expr 30.437 * $M]
return [expr {$days + ((($h *3600) + ($m * 60) + $s)/86400.0)}]
}
lappend PUNKARGS [list {
@id -id ::winlibreoffice::from_libre_date
@cmd -name winlibreoffice::from_libre_date -help\
"Convert an internal Libre Office date floating point value
representing the number of days since 1899-12-30 to a format
understood by Tcl such as 'clock seconds', 'clock milliseconds'
as specified in the -format option.
"
@opts
-format -default "clockseconds" -choices {clockseconds clockmillis ISO8601} -choicerestricted 0 -help\
"Aside from the special values listed -format accepts a format string
as accepted by the Tcl 'clock format' command's -format option."
-timezone -default "" -help\
"If unspecified, the timezone will be the
current time zone on the system"
@values -min 1 -max 1
libredatetime -type float -help\
"Floating point number representing the number of
days since 1899-12-30."
}]
#review - we don't expect sci notation for any float values here
#but we could easily get them.. e.g 0.000000001 * 86400.0 => 8.64e-5
#todo - clockmicros ?
proc from_libre_date {args} {
package require punk::args
set argd [punk::args::parse $args withid ::winlibreoffice::from_libre_date]
lassign [dict values $argd] leaders opts values received
set format [dict get $opts -format]
set tz [dict get $opts -timezone]
set libredatetime [dict get $values libredatetime]
#yes.. this is horrible.. just a test really - but gets in the ballpark.
return [expr int($yeardays + $monthdays + $D)]
variable datebase
set tbase [clock scan $datebase -timezone $tz]
set intdays [expr {int($libredatetime)}]
set fracdays [lindex [split $libredatetime .] 1]
if {$fracdays ne ""} {
set fracdays "0.$fracdays"
set floatsecs [expr {$fracdays * 86400.0}] ;#assuming not a leap-second day
if {$format eq "clockmillis"} {
set wholesecs [expr {int($floatsecs)}]
set msfrac [lindex [split $floatsecs .] 1]
if {$msfrac ne ""} {
set msfrac "0.$msfrac" ;#could also be something like 0.64e-5 which should still work
set ms [expr {round(1000 * $msfrac)}]
if {$ms == 1000} {
set ms 0
incr wholesecs
}
} else {
set ms 0
}
} else {
set wholesecs [expr {round($floatsecs)}]
set ms 0
}
} else {
set wholesecs 0
set ms 0
}
set cs [clock add $tbase +$intdays days +$wholesecs seconds -timezone $tz]
switch -- $format {
clockseconds {
return $cs
}
clockmillis {
return [expr {($cs * 1000) + $ms}]
}
ISO8601 {
set format "%Y%m%dT%H%M%S"
}
}
return [clock format $cs -format $format]
}
#time is represented on a scale of 0 to 1 6:00am = 0.25 (24/4)
proc date_from_clockseconds {cs} {
puts stderr "unimplemented"
#return libreoffice date as a floating point number of days since 1899.. (1899-12-30)
proc to_libre_date_from_clockseconds_gmt {cs} {
return [expr {($cs/86400.0) + 25569}]
}
#see also: https://wiki.tcl-lang.org/page/Tcom+examples+for+Microsoft+Outlook
@ -265,19 +367,21 @@ namespace eval winlibreoffice {
# -----------------------------------------------------------------------------
# register namespace(s) to have PUNKARGS,PUNKARGS_aliases variables checked
# -----------------------------------------------------------------------------
# variable PUNKARGS
# variable PUNKARGS_aliases
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
lappend ::punk::args::register::NAMESPACES ::winlibreoffice
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
## Ready
package provide winlibreoffice [namespace eval winlibreoffice {
variable version
set version 999999.0a1.0
set version 999999.0a1.0
}]
return

Loading…
Cancel
Save