@@ -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
105107week_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