Skip to content

Commit ea284fd

Browse files
committed
opt: update ical-week
1 parent a1bb9ae commit ea284fd

1 file changed

Lines changed: 35 additions & 72 deletions

File tree

opt/graveyard/opt/ical-week/bin/ical-week

Lines changed: 35 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ warn() {
8484
#
8585
# These options are not appropriate to obtain the week number used by
8686
# Calendar.app. Instead, January 1 is Week 1 *always*, which consequently
87-
# means Week 53 only occurs in Calendar.app if December 31 is a Sunday.
87+
# means Week 53 only occurs in Calendar.app if December 31 is a Saturday.
8888
#
8989
# The days that `date` considers start of week for its various week number
9090
# options also complicate things.
@@ -99,83 +99,46 @@ warn() {
9999
# - %W: is also close to what we want, like %U, but its week starts on a
100100
# Monday.
101101
#
102-
# With all that in mind, we reach for NSDate which does what we want.
102+
# With all that in mind, we calculate the week number using the same
103+
# algorithm as NSCalendar/ICU: week = floor((dayOfYear - 1 + dow(Jan1)) / 7) + 1
104+
# with Sunday as the first day of the week and minimumDaysInFirstWeek = 1.
103105
#
104-
# See https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_from_a_month_and_day_of_the_month_or_ordinal_date
106+
# See https://en.wikipedia.org/wiki/ISO_week_date
105107
week_number() {
106-
local now="$1" pad="$2" start_or_end="$3" week
107-
108-
# https://gist.github.com/RichardHyde/3386ac57b55455b71140
109-
week=$( osascript -e "
110-
use scripting additions
111-
use framework \"Foundation\"
112-
113-
on getWeekFromDate(theDate)
114-
try
115-
set theASDate to theDate as date
116-
set theNSDate to current application's NSDate's dateWithTimeInterval:0 sinceDate:theASDate
117-
set theNSCalendar to current application's NSCalendar's currentCalendar()
118-
set theWeekInteger to (theNSCalendar's component:(current application's NSCalendarUnitWeekOfYear) fromDate:theNSDate) as integer
119-
return theWeekInteger
120-
on error
121-
return -1 as integer
122-
end try
123-
end getWeekFromDate
124-
125-
-- Convert date function. Call with string in YYYY-MM-DD HH:MM:SS format (time part optional)
126-
on convertDate(textDate)
127-
set resultDate to the current date
128-
set the month of resultDate to (1 as integer)
129-
set the day of resultDate to (1 as integer)
130-
131-
set the year of resultDate to (text 1 thru 4 of textDate)
132-
set the month of resultDate to (text 6 thru 7 of textDate)
133-
set the day of resultDate to (text 9 thru 10 of textDate)
134-
set the time of resultDate to 0
135-
136-
return resultDate
137-
end convertDate
138-
139-
on pad(v)
140-
return text -2 thru -1 of ((v + 100) as text)
141-
end pad
142-
143-
-- get start/end day of week
144-
on getStartEndOfDayWeek(theTarget, theDate)
145-
set theWeekdays to {\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"}
146-
set theWeekday to weekday of theDate as string
147-
148-
repeat with i from 1 to (count theWeekdays)
149-
if item i of theWeekdays = theWeekday then exit repeat
150-
end repeat
151-
152-
if theTarget = \"start\" then
153-
set theResult to theDate - (i - 1) * days
154-
else
155-
set theResult to theDate + (7 - i) * days
156-
end if
157-
158-
-- return YYYY-MM-DD format
159-
return (year of theResult as string) & \"-\" & pad(month of theResult as integer) & \"-\" & pad(day of theResult as integer)
160-
end getStartEndOfDayWeek
161-
162-
on run argv
163-
if (item 1 of argv) = \"start\"
164-
return getStartEndOfDayWeek(\"start\", convertDate(item 2 of argv))
165-
else if (item 1 of argv) = \"end\"
166-
return getStartEndOfDayWeek(\"end\", convertDate(item 2 of argv))
167-
else
168-
return getWeekFromDate(convertDate(item 2 of argv))
169-
end if
170-
end run
171-
" "$start_or_end" "$now"
172-
)
108+
local now="$1" pad="$2" start_or_end="$3"
173109

174110
if [[ "$start_or_end" ]]; then
175-
printf "%s" "$week"
111+
local dow
112+
dow=$(date -j -f "%F" "$now" "+%w")
113+
if [[ "$start_or_end" == "start" ]]; then
114+
printf "%s" "$(date -j -v-${dow}d -f "%F" "$now" "+%F")"
115+
else
116+
printf "%s" "$(date -j -v+$((6 - dow))d -f "%F" "$now" "+%F")"
117+
fi
118+
return
119+
fi
120+
121+
local year="${now:0:4}"
122+
local day_of_year dow dow_jan1 days_in_year week
123+
124+
read -r day_of_year dow < <(date -j -f "%F" "$now" "+%j %w")
125+
dow_jan1=$(date -j -f "%F" "${year}-01-01" "+%w")
126+
127+
if (( year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) )); then
128+
days_in_year=366
176129
else
177-
printf "%${pad}d" "$week"
130+
days_in_year=365
178131
fi
132+
133+
# If the date's week (Sun-Sat) extends into the next year,
134+
# NSCalendar considers it week 1 of the next year
135+
if (( 10#$day_of_year + 6 - dow > days_in_year )); then
136+
week=1
137+
else
138+
week=$(( (10#$day_of_year - 1 + dow_jan1) / 7 + 1 ))
139+
fi
140+
141+
printf "%${pad}d" "$week"
179142
}
180143

181144
# Print the help text for this program

0 commit comments

Comments
 (0)