Archive for the '日付、カレンダー関連(calendar)' Category

2016/04/13 ISO8601日付文字列を生成

NSDateからISO8601日付文字列を生成するAppleScriptです。

昨日のGHKitによるISO8601日付文字列ではいまひとつDropbox側と仕様が合わず、ちょっと困ってしまいました。

いくつものXcode Projectをgithub上で探してビルドしては捨て、捨ててはビルドしての繰り返しをしていました。ソースが古いとARC対応していなかったりして、かなり書き換える必要が生じてしまいます。

が、そもそも別にそんなたいしたものでもないので(^ー^;; 「自分で書いた方が簡単なんじゃないの?」と気付き、さらっと書きました。

これで、REST API経由でAppleScriptからDropboxを小突きまわして、ファイル共有期限の日時指定を行えます。

AppleScript名:ISO8601日付文字列を生成
– Created 2016-04-13 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlust : script “BridgePlus” –for OS X 10.10.x

set aDate to (current date) + 3 * days
set bDate to Cocoaify aDate
set bStr to retISO8601DateTimeString(aDate) as string
–> “2016-04-16T09:23:11Z”

–NSDate -> ISO8601 Date & Time String for Dropbox
on retISO8601DateTimeString(targDate)
  set theNSDateFormatter to current application’s NSDateFormatter’s alloc()’s init()
  
theNSDateFormatter’s setDateFormat:“yyyy-MM-dd’T’HH:mm:ss’Z’”
  
theNSDateFormatter’s setTimeZone:(current application’s NSTimeZone’s alloc()’s initWithName:“UTC”)
  
return (theNSDateFormatter’s stringFromDate:targDate) as text
end retISO8601DateTimeString

★Click Here to Open This Script 

2016/04/12 GHKitで日付フォーマット変換

Gabriel Handford氏によるオープンソースのフレームワーク「GHkit」を利用して、さまざまなフォーマットの日付表現のNSDateとの相互変換(decode/encode)を行うAppleScriptです。

REST経由でさまざまなサービスを呼び出して使っていると、さまざまな形式のタイムスタンプの文字列を扱い、parseする必要に迫られるため、こういう種類のフレームワークがあるのではないかと考えて探したところ見つけました。

オリジナルでは、GHKitの各メソッド名が「gh_」という形式になっており、これ(アンダースコア)がAppleScriptにおけるObjective-Cのメソッド名変換時に問題になったため、Xcode上で自分ですべてリネームして使っています(汗)。

なお、OS X 10.10以降用にビルドしたFrameworkのバイナリを用意しましたので、使ってみたい方はアーカイブを展開したあと~/Library/Frameworksに入れてご利用ください(自己責任で)。

–> Download Framework Binary

AppleScript名:GHKitで日付フォーマット変換
– Created 2016-04-12 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “GHKit” –https://github.com/gabriel/GHKit

– AppleScriptObjC uses “_” as special character (equivalent to “:” in method names). So, I changed them in whole project.
–  Original Method Name: gh_parseISO8601:
–  Converted Method Name: GHparseISO8601:

–Decode RFC822, ISO8601& HTTP format date strings

set aStr to current application’s NSString’s stringWithString:“Sun, 06 Nov 1994 08:49:37 +0000″
set aDate to current application’s NSDate’s GHparseRFC822:aStr
–>  (NSDate) 1994-11-06 08:49:37 +0000

set bStr to current application’s NSString’s stringWithString:“1997-07-16T19:20:30.045Z” –For Dropbox file/folder sharing expiration format
set bDate to current application’s NSDate’s GHparseISO8601:bStr
–>  (NSDate) 1997-07-16 19:20:30 +0000

set cStr to current application’s NSString’s stringWithString:“Tue, 12 Apr 2016 06:28:45 GMT” –Dropbox REST Result header timestamp format
set cDate to current application’s NSDate’s GHparseHTTP:cStr
–>  (NSDate) 2016-04-12 06:28:45 +0000

–Encode NSDate to RFC822, ISO8601& HTTP format date strings

set eDateStr to bDate’s GHformatHTTP()
–>  (NSString) “Wed, 16 Jul 1997 19:20:30 GMT” –For Dropbox file/folder sharing expiration format

set fDateStr to bDate’s GHformatRFC822()
–>  (NSString) “Wed, 16 Jul 1997 19:20:30 +0000″

set gDateStr to bDate’s GHformatISO8601()
–>  (NSString) “1997-07-17T04:20:30.045+09:00″

★Click Here to Open This Script 

2016/02/10 ISO8601ちっくな週カウント

Cocoaの機能を用いて指定日付が1年のうちの何週目にあたるか、一般常識的なカウントと、ISO8601で規定されている週カウントの両方で計算するAppleScriptです。

iso8601wc.png

ISO8601で規定している週番号では、1/1が木曜日から土曜日までの間にある場合には前年の12月の最終週の続きとして扱われます。aWNがiCalの画面上に表示される週番号、bWNがISO8601に則ってカウントした週番号です。

AppleScript名:ISO8601ちっくな週カウント
– Created 2016-02-10 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aNSDate to makeNSDate(2016, 1, 1) of me
set aCal to current application’s NSCalendar’s currentCalendar()
aCal’s setMinimumDaysInFirstWeek:1
set aWN to (aCal’s components:(current application’s NSWeekCalendarUnit) fromDate:aNSDate)’s week()

aCal’s setMinimumDaysInFirstWeek:4 –ISO8601 Week Count
set bWN to (aCal’s components:(current application’s NSWeekCalendarUnit) fromDate:aNSDate)’s week()

return {aWN, bWN}
–>  {1, 52}

–Y,M,Dを指定してNSDateを作成
on makeNSDate(aYear as integer, aMonth as integer, aDay as integer)
  set aComp to current application’s NSDateComponents’s alloc()’s init()
  
aComp’s setDay:aDay
  
aComp’s setMonth:aMonth
  
aComp’s setYear:aYear
  
set aGrego to current application’s NSCalendar’s calendarWithIdentifier:(current application’s NSGregorianCalendar)
  
set aDate to aGrego’s dateFromComponents:aComp
  
return aDate
end makeNSDate

★Click Here to Open This Script 

2016/01/18 2つの日付の期間を日本語表記でていねいに返す

Pure AppleScriptで、与えられた2つの日付から開始日–>終了日の期間を示す文字列を組み立てて返すAppleScriptです。

Pure AppleScriptのdate objectを利用しているので、localeとかカレンダーの時間帯は一切考慮していません。

OS標準のNSDateIntervalFormatterのJapanese(JST)localeにおける処理があまりにも「そりゃないよ」というレベルだったので、ちょっと書いてみました。

場合によっては曜日の併記を求められるケースがあるでしょうし、これがそのまますべてのケースにおいて使えるわけではないとは思いますが、世間一般的にはこのぐらいはしてほしい気がします。

AppleScript名:2つの日付の期間を日本語表記でていねいに返す
– Created 2016-01-17 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

–Date Difference
set sDate to "2016/1/15" –Japanese Date format "YYYY/MM/DD"
set eDate to "2016/1/20" –Japanese Date format "YYYY/MM/DD"
set aDiffStr to retDateDiffStr(sDate, eDate, "/", "/", "", "〜") of me
–> "2016/1/15〜20"

–Month Difference
set sDate to "2016/1/15" –Japanese Date format "YYYY/MM/DD"
set eDate to "2016/2/20" –Japanese Date format "YYYY/MM/DD"
set bDiffStr to retDateDiffStr(sDate, eDate, "年", "月", "日", "〜") of me
–> "2016年1月15日〜2月20日"

–Year Difference
set sDate to "2015/12/15" –Japanese Date format "YYYY/MM/DD"
set eDate to "2016/1/20" –Japanese Date format "YYYY/MM/DD"
set bDiffStr to retDateDiffStr(sDate, eDate, "年", "月", "日", "〜") of me
–> "2015年12月15日〜2016年1月20日"

–2つの日付の期間を日本語表記でていねいに返す
on retDateDiffStr(sDate, eDate, ySeparator, mSeparator, dSeparator, diffSeparator)
  
  
set sDateO to date sDate
  
set eDateO to date eDate
  
  
set diffY to (year of eDateO) - (year of sDateO)
  
set diffM to (month of eDateO) - (month of sDateO)
  
set diffD to (day of eDateO) - (day of sDateO)
  
  
set sYstr to (year of sDateO) as string
  
set sMstr to (month of sDateO as number) as string
  
set sDstr to (day of sDateO) as string
  
  
set eYstr to (year of eDateO) as string
  
set eMstr to (month of eDateO as number) as string
  
set eDstr to (day of eDateO) as string
  
  
if diffY > 0 then
    –Year Difference
    
set outStr to sYstr & ySeparator & sMstr & mSeparator & sDstr & dSeparator & diffSeparator & eYstr & ySeparator & eMstr & mSeparator & eDstr & dSeparator
  else if diffM > 0 then
    –Month Difference
    
set outStr to sYstr & ySeparator & sMstr & mSeparator & sDstr & dSeparator & diffSeparator & eMstr & mSeparator & eDstr & dSeparator
  else if diffD > 0 then
    –Date Difference
    
set outStr to sYstr & ySeparator & sMstr & mSeparator & sDstr & diffSeparator & eDstr & dSeparator
  end if
  
  
return outStr
  
end retDateDiffStr

★Click Here to Open This Script 

2015/02/25 Conversion between UTCTime String and NSDate

Conversion ASOC script between UTCTime String (with milli-seconds) and NSDate.

In US Apple’s AppleScript Users ML, I saw the thread “UTC time with milliseconds”.

They talk about only current date -> UTCTime string (with milli-seconds) . And there is no care of each time zone.

So, I added time zone consideration and reverse conversion handler.

Reverse conversion (UTCTime string -> NSDate) does not need to get users time zone, I think.

Ole Begemann’s Working with Date and Time in Cocoa was very useful and helpful for me.

Shane Stanley taught me this is not right. Oh! my Buddha! (something like God..)

I misunderstood the definition of the word “UTCTime”. I meant it as a time string. So, I’ll fix this later. Hmm..I don’t need to get “UTCTime” string….Is there any need to get it?

AppleScript名:UTCTime StringとNSDateの相互変換
– Created 2015-02-24 by Shane Stanley
– Changed 2015-02-25 By Takaaki Naganoya
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aStr to retUTCTimeString()
–>   “2015-02-25T13:49:55.713″

set aNSDate to retNSDateFromUTCString(aStr)
–>  (NSDate) 2015-02-25 13:49:55 +0000 –ASObjC Explorer
–> «class ocid» id «data optr0000000030F7400000600000» –Apple’s Script Editor

–Current Date -> UTCTime String
on retUTCTimeString()
  –There is need to get Current Calendar in my Time Zone
  
set aCalendar to current application’s NSCalendar’s currentCalendar()
  
set aTimeZone to (aCalendar’s timeZone)
  
set tDiff to (aTimeZone’s secondsFromGMT())
  
  
set theNSDateFormatter to current application’s NSDateFormatter’s alloc()’s init()
  
  
theNSDateFormatter’s setDateFormat:“yyyy-MM-dd’T’HH:mm:ss.SSS”
  
theNSDateFormatter’s setTimeZone:(current application’s NSTimeZone’s timeZoneForSecondsFromGMT:tDiff)
  
  
return (theNSDateFormatter’s stringFromDate:(current application’s NSDate’s |date|())) as text
end retUTCTimeString

–UTCTime String -> NSDate
on retNSDateFromUTCString(aText)
  set aStr to current application’s NSString’s stringWithString:aText
  
  
set theNSDateFormatter to current application’s NSDateFormatter’s alloc()’s init()
  
theNSDateFormatter’s setDateFormat:“yyyy-MM-dd’T’HH:mm:ss.SSS”
  
theNSDateFormatter’s setTimeZone:(current application’s NSTimeZone’s timeZoneForSecondsFromGMT:0)
  
  
return theNSDateFormatter’s dateFromString:aStr
end retNSDateFromUTCString

★Click Here to Open This Script 

2015/02/02 2月1日が日曜日でうるう年ではないかチェック(ASOC)

先日の「2月1日が日曜日でうるう年ではない(1日から28日までびっしり数字が入っている)」年を検出する(技術の無駄遣い的な ^ー^;)AppleScriptのASOC版です。Shane Stanleyが送ってくれました(こんなくだらないScriptに付き合わせて申し訳ない、、、)。

3,000年分計算して、だいたい0.8秒ぐらい。Pure AppleScript版より2倍以上高速ですが、3,000年程度の計算ではASOCの真の力が発揮できません。

AppleScript名:2月1日が日曜日でうるう年ではないかチェック(ASOC)
– Created 2015-02-02 by Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set resYList to {} –hit year

set theNSCalendar to current application’s NSCalendar’s currentCalendar() – do *not* use initWithCalendarIdentifier:

repeat with y from 0 to 3000
  set aMlen to getMlenAndVerifyFirstDaysNum(y, 2, theNSCalendar, 28, 1) of me
  
if aMlen = true then
    set the end of resYList to y
  end if
  
–set the end of resYList to aMlen
end repeat

return resYList

on getMlenAndVerifyFirstDaysNum(aYear, aMonth, theNSCalendar, dMax, fdayNum)
  
  
–現在のLocaleのCalendarで指定年月の日数をかぞえる
  
set theDate to theNSCalendar’s dateWithEra:1 |year|:aYear |month|:aMonth |day|:1 hour:0 minute:0 |second|:0 nanosecond:0
  
set theResult to theNSCalendar’s rangeOfUnit:(current application’s NSDayCalendarUnit) inUnit:(current application’s NSMonthCalendarUnit) forDate:theDate
  
–>  {location:1, length:31}
  
set mLen to |length| of theResult
  
  
–指定年月の1日を取得
  
set theDay to theNSCalendar’s components:((current application’s NSWeekdayCalendarUnit) + (current application’s NSMonthCalendarUnit as integer)) fromDate:theDate
  
  
–指定年月の1日の曜日が指定曜日で、うるう月でなく、指定年月の日数が指定日数(dMax)であるか判定
  
if (theDay’s |weekday|() = fdayNum) and (theDay’s isLeapMonth() is false) and (mLen = dMax) then
    return true
  else
    return false
  end if
  
end getMlenAndVerifyFirstDaysNum

★Click Here to Open This Script 

2015/02/02 国際化対応Mlen ASOC版

Shane Stanleyが送ってくれた、国際化対応MlenのASOC版(を、いろいろ検証して修正したもの)です。

そもそも、「Mlen」とは何か? 指定月(例:2012年2月)の日数を求めるMonth Length計算ルーチンです。そして、日本語環境だけではなく他の言語環境でも動くように配慮したものを「国際化対応Mlen」と呼んでいます。

Cocoaの機能を呼び出すようにした本バージョンでは、スピードアップが図られてはいますが、さすがに極小データの処理だけなので数千回ループで回してようやく「速い」とわかるぐらいです。数万件とか数十万件のオーダーになってくると、3倍以上高速かな? という感じです。

AppleScript名:getMlenInternational_ASOC
– Created 2015-02-02 by Shane Stanley
– Modified 2015-02-02 by Takaaki Naganoya
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set mList to {}
repeat with m from 1 to 12
  set the end of mList to getMlenInternational(2012, m) of me –2012 is a Leap Year–2012年はうるう年
end repeat
mList
–>  {​​​​​31, ​​​​​29, ​​​​​31, ​​​​​30, ​​​​​31, ​​​​​30, ​​​​​31, ​​​​​31, ​​​​​30, ​​​​​31, ​​​​​30, ​​​​​31​​​}

–現在のカレンダーで指定年月の日数を返す
on getMlenInternational(aYear, aMonth)
  –From Shane’s getMlenInternational(ASOC) v1
  
set theNSCalendar to current application’s NSCalendar’s currentCalendar() – do *not* use initWithCalendarIdentifier:
  
set theDate to theNSCalendar’s dateWithEra:1 |year|:aYear |month|:aMonth |day|:1 hour:0 minute:0 |second|:0 nanosecond:0
  
set theResult to theNSCalendar’s rangeOfUnit:(current application’s NSDayCalendarUnit) inUnit:(current application’s NSMonthCalendarUnit) forDate:theDate
  
–>  {location:1, length:31}
  
return |length| of theResult
end getMlenInternational

★Click Here to Open This Script 

2015/02/01 うるう年ではない年の2月で日曜日はじまりのものを返す

Twitter上で拡散されたデマ「日曜日から土曜日まで当てはまるのは今月が823年ぶり」に対して、実際にプログラムを組んで「そんなことはない」と反論されている人がいるのを見て、感心して同様のプログラムをAppleScriptでも作ってみました。

cal823.png

3,000年分を計算してMacBook Pro Retina 2012で1.7秒程度。サブルーチン部分は作り置きしていたものをそのまま再利用しただけなので、書くのに5分かかっていませんが、びみょーに見た目が長く見えるのは・・・そもそもAppleScriptの処理系にこういう計算を行う機能がないからです。

せっかくなので、AppleScriptObjCでCocoaの機能を呼び出して高速化してみようかとも思いましたが、こんなに手軽には書けず、しかもスピードアップの度合いが低い(3,000件ではデータが少なすぎて話にならない)ので途中で投げてしまいました。

注意:本Script中の「retDateOwithParam」はcurrent dateからdate objectを取得してパラメータを書き換えていますが、日付がズレる可能性があるのでこのやりかたは使わないでください。詳細については書籍「AppleScript最新リファレンス」にて解説しています。

AppleScript名:2月1日が日曜日でうるう年ではないかチェック
– Created 2015-02-01 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions

set resYList to {} –hit year

repeat with y from 0 to 3000
  
  
set aMlen to getMlenInternational(y, 2) of me
  
  
if aMlen = 28 then
    set aDatO to retDateOwithParam(y, 2, 1, 0, 0, 0)
    
set aWkd to (weekday of aDatO as number)
    
    
–y/2/1 = Sunday
    
if aWkd = 1 then
      set the end of resYList to y
    end if
  end if
end repeat

return resYList
–>  {9, 15, 26, 37, 43, 54, 65, 71, 82, 93, 99, 105, 111, 122, 133, 139, 150, 161, 167, 178, 189, 195, 201, 207, 218, 229, 235, 246, 257, 263, 274, 285, 291, 303, 314, 325, 331, 342, 353, 359, 370, 381, 387, 398, 409, 415, 426, 437, 443, 454, 465, 471, 482, 493, 499, 505, 511, 522, 533, 539, 550, 561, 567, 578, 589, 595, 601, 607, 618, 629, 635, 646, 657, 663, 674, 685, 691, 703, 714, 725, 731, 742, 753, 759, 770, 781, 787, 798, 809, 815, 826, 837, 843, 854, 865, 871, 882, 893, 899, 905, 911, 922, 933, 939, 950, 961, 967, 978, 989, 995, 1001, 1007, 1018, 1029, 1035, 1046, 1057, 1063, 1074, 1085, 1091, 1103, 1114, 1125, 1131, 1142, 1153, 1159, 1170, 1181, 1187, 1198, 1209, 1215, 1226, 1237, 1243, 1254, 1265, 1271, 1282, 1293, 1299, 1305, 1311, 1322, 1333, 1339, 1350, 1361, 1367, 1378, 1389, 1395, 1401, 1407, 1418, 1429, 1435, 1446, 1457, 1463, 1474, 1485, 1491, 1503, 1514, 1525, 1531, 1542, 1553, 1559, 1570, 1581, 1587, 1598, 1609, 1615, 1626, 1637, 1643, 1654, 1665, 1671, 1682, 1693, 1699, 1705, 1711, 1722, 1733, 1739, 1750, 1761, 1767, 1778, 1789, 1795, 1801, 1807, 1818, 1829, 1835, 1846, 1857, 1863, 1874, 1885, 1891, 1903, 1914, 1925, 1931, 1942, 1953, 1959, 1970, 1981, 1987, 1998, 2009, 2015, 2026, 2037, 2043, 2054, 2065, 2071, 2082, 2093, 2099, 2105, 2111, 2122, 2133, 2139, 2150, 2161, 2167, 2178, 2189, 2195, 2201, 2207, 2218, 2229, 2235, 2246, 2257, 2263, 2274, 2285, 2291, 2303, 2314, 2325, <
>}

on getMlenInternational(aYear, aMonth)
  set sDat to retDateOwithParam(aYear, aMonth, 1, 0, 0, 0) of me
  
if aMonth is not equal to 12 then
    set eDat to retDateOwithParam(aYear, aMonth + 1, 1, 0, 0, 0) of me
  else
    set eDat to retDateOwithParam(aYear + 1, 1, 1, 0, 0, 0) of me
  end if
  
  
set eDat to eDat - 1
  
  
set mLen to day of eDat
  
  
return mLen
end getMlenInternational

–国際化対応 パラメータによるdateオブジェクト作成ルーチン
on retDateOwithParam(yearNum, monthNum, dateNum, hourNum, minuteNum, secondNum)
  set aDateO to current date
  
  
set year of aDateO to yearNum
  
set month of aDateO to monthNum
  
set day of aDateO to dateNum
  
set hours of aDateO to hourNum
  
set minutes of aDateO to minuteNum
  
set seconds of aDateO to secondNum
  
  
return aDateO
  
end retDateOwithParam

★Click Here to Open This Script 

2014/11/06 現在のLocaleのカレンダーの最初の曜日を取得する

現在のログイン中のユーザーアカウントで(システム環境設定の「言語と地域」で)設定しているカレンダーにおける、どの曜日で始まるかの設定を取得するAppleScriptです。

cal1.png

cal2.png

AppleScript名:asoc_現在のLocateのカレンダーの最初の曜日を取得する v2
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aCalendar to current application’s NSCalendar’s currentCalendar()
set aFirstDay to (aCalendar’s firstWeekday)
set c to aFirstDay as integer
–> 1 (Sunday Start Calendar)

–フランス、香港などは月曜日がカレンダーの先頭に来るため結果が異なる
–> 2 (Monday Start Calendar)

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/11/05 秒以下の単位で時間計測

Cocoaの機能を利用して、秒以下の単位で時間計測を行うAppleScriptです。

US AppleのAppleScriptObjC Users MLでShane Stanleyから「ベンチマーク的な時間計測ならこっちの方が」と教えてもらったものです。

NSDateのtimeIntervalSinceReferenceDateメソッドを利用し、システムの絶対基準日(2001年1月1日 00:00:00 GMT)と現在の日時との間隔を取得、AppleScriptで秒以下の単位での計測が可能になります。

Macの新製品が出ると、Apple StoreなどでAppleScriptを打ち込んで時間計測していますが(なんか、1980年代のノリみたいだ。家電屋に置かれていた8ビットのパソコンにBASICのプログラムを入力して時間を計っていた、、)、秒単位以下の計測がすぐにできれば、10倍とか100倍のループを回して細かい時間を取得するといったことも不要に、、、

AppleScript名:asoc_秒以下の単位で時間計測
–By Shane Stanley

use AppleScript version “2.4″
use framework “Foundation”
use scripting additions

set a1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate()

delay 5

set b1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate()
set c1Dat to b1Dat - a1Dat

–> 5.016112983227–マシンの実行速度によって違うはず

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/11/04 現在のLocaleのカレンダーのTime Zoneを取得する

現在ログイン中のカレンダー(設定)を取得し、Time Zone名や時差の情報を取得するAppleScriptです。

sys1.png

sys2.png

言語設定によっては、OSレベルで管理しているカレンダーが「日曜日で始まる」か「月曜日で始まる」かといった違いがあります。こうした情報にアクセスするための習作として作成したものです。

GMTとの時差であれば、通常のAppleScriptでも(大昔から)取得できるようになっていますが、どの曜日からカレンダーが始まるかという情報は、Cocoaにアクセスしないとわからないため外せません。

AppleScript名:asoc_現在のLocaleのカレンダーのTime Zoneを取得する
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aCalendar to current application’s NSCalendar’s currentCalendar()
set aTimeZone to (aCalendar’s timeZone)
set tzName to aTimeZone’s |name|() as string
–> “Asia/Tokyo”

set tDiff to (aTimeZone’s secondsFromGMT()) / 3600
–> 9.0

set aDesc to aTimeZone’s |description|() as string
–> “Asia/Tokyo (JST) offset 32400″

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

AppleScript名:普通のASでGMTとの時差を求める
set tDIff to (time to GMT) / 3600
–> 9.0

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/07/29 dateオブジェクトの加減算

dateオブジェクトの加減算の記述例です。

たとえば、現在時刻(current date)の1時間後を求めるのに……

スクリプト名:現在の1時間後を求める(ダメな例)
set a to current date

set tmpH to hours of a
set tmpH to tmpH + 1
set hours of a to tmpH

a
–> date "2014年7月29日火曜日 10:07:46"

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

と書いている例に見当たりましたが……この調子で3時間20分3秒後を計算しようとすると……

スクリプト名:現在の3時間20分3秒後を求める(ダメな例)
set a to current date

set tmpH to hours of a
set tmpH to tmpH + 3
set hours of a to tmpH

set tmpM to minutes of a
set tmpM to tmpM + 20
set minutes of a to tmpM

set a to a + 3

a
–> date "2014年7月29日火曜日 22:54:10"

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

のようになるので、たいへんです。

dateオブジェクトに対しての加減算は、秒単位で数値を足したり引いたりすることで計算できます。

そのさいに、分(minutes=60)、時(hours=3600)、日(days=86400)、週(weeks=604800)などの定数があらかじめ定義されているため、これらを用いることになります。

スクリプト名:現在の1時間後を求める
set a to current date

set a to a + (1 * hours)

–> date "2014年7月29日火曜日 10:07:46"

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

スクリプト名:現在の1時間前を求める
set a to current date

set a to a - (1 * hours)

–> date "2014年7月29日火曜日 10:07:46"

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

スクリプト名:現在の1日後を求める
set a to current date

set a to a + (1 * days)
–> date "2014年7月30日水曜日 11:18:23"

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

スクリプト名:現在の1日前を求める
set a to current date

set a to a - (1 * days)
–> date "2014年7月28日月曜日 19:28:52"

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

スクリプト名:現在の3時間20分3秒後を求める
set a to current date

set a to a + (3 * hours) + (20 * minutes) + (3)
–> date "2014年7月29日火曜日 12:29:41"

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

スクリプト名:現在の3時間20分3秒前を求める
set a to current date

set a to a - ((3 * hours) + (20 * minutes) + (3))
–> date "2014年7月29日火曜日 12:29:41"

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/05/13 選択中のフォルダ内のすべてのファイルの作成日、変更日をcurrent dateに変更 v2

Finder上で選択中のフォルダ内のすべてのファイル/フォルダの作成日、変更日を現在時刻に変更するAppleScriptの、OS X 10.9対応版です。

実行のためには、Xcodeのインストールが必要です(/usr/bin/SetFileコマンド)。

currentdater.png

Script Menuに入れて、サンプルのXcodeプロジェクトの作成日/修正日の日付をまとめて変更するために作ったものです。

スクリプト名:選択中のフォルダ内のすべてのファイルの作成日、変更日をcurrent dateに変更 v2
set aCurDate to current date
set aDateStr to makeMMDDYYYYhhmmssStr(aCurDate) of me

tell application “Finder”
  set aSel to selection as alias list
  
if aSel = {} or aSel is equal to missing value then
    display dialog “何も選択されていません。” buttons {“OK”} default button 1
    
return
  end if
end tell

repeat with i in aSel
  
  
set j to contents of i
  
set aKind to detectFolder(j) of me
  
  
–選択中のアイテムがフォルダの場合にはその中のファイル一覧を取得
  
set fList to {}
  
  
if aKind = true then
    tell application “Finder”
      tell folder (j as string)
        set fList to entire contents as alias list
      end tell
    end tell
  else
    –選択中のアイテムがファイルの場合にはそのままリストに入れる
    
set fList to {j}
  end if
  
  

  
repeat with i in fList
    set j to contents of i
    
set aFres to detectFolder(i) of me
    
changeCreationDate(j, aDateStr) of me
  end repeat
  
end repeat

–aliasがFolderかどうか判定
on detectFolder(aSelFol)
  set aInfo to info for aSelFol as alias
  
tell application “Finder”
    try
      set aFol to kind of aInfo
    on error
      return false
    end try
  end tell
  
  
return (aFol = “フォルダ”) –”Folder” in Japanese, change here to each localized string
end detectFolder

–作成日と修正日を変更する
on changeCreationDate(aFile, aDateStr)
  set bP to POSIX path of aFile
  
  
try
    do shell script “/usr/bin/SetFile -d “ & quoted form of aDateStr & ” “ & quoted form of bP –作成日
    
do shell script “/usr/bin/SetFile -m “ & quoted form of aDateStr & ” “ & quoted form of bP –修正日
  end try
  
end changeCreationDate

–DateオブジェクトからMM/DD/YYYY hh:mm:ssの形式の文字列を返す
on makeMMDDYYYYhhmmssStr(aDate)
  –Dateオブジェクトから各要素を取り出す
  
set yStr to (year of aDate) as string
  
set mStr to (month of aDate as number) as string
  
set dStr to (day of aDate) as string
  
set hhStr to (hours of aDate) as string
  
set mmStr to (minutes of aDate) as string
  
set ssStr to (seconds of aDate) as string
  
  
–桁数を合わせる
  
set y2Str to retZeroPaddingText(yStr, 4) of me
  
set m2Str to retZeroPaddingText(mStr, 2) of me
  
set d2Str to retZeroPaddingText(dStr, 2) of me
  
set hh2Str to retZeroPaddingText(hhStr, 2) of me
  
set mm2Str to retZeroPaddingText(mmStr, 2) of me
  
set ss2Str to retZeroPaddingText(ssStr, 2) of me
  
  
return (m2Str & “/” & d2Str & “/” & y2Str & ” “ & hh2Str & “:” & mm2Str & “:” & ss2Str)
end makeMMDDYYYYhhmmssStr

–数値にゼロパディングしたテキストを返す
on retZeroPaddingText(aNum, aLen)
  set tText to (“0000000000″ & aNum as text)
  
set tCount to length of tText
  
set resText to text (tCount - aLen + 1) thru tCount of tText
  
return resText
end retZeroPaddingText

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/09/08 AppleScriptObjCで国民の祝日を計算

2013/09/06 ASOCでカレンダー作成・表示テスト

AppleScriptで作成したさまざまな部品を組み合わせて、AppleScriptObjCでカレンダー表示を行ってみました。

単に、NSMatrixの中にNSButtonを作っておいて、リストのカレンダーを順次流し込んでいます。

calt1.png
▲サンプルの画面

calt3.png
▲後日、Xcode上でデザインをブラッシュアップしたもの(作業途上)

出来上がりもたいしたことはなく、記述量も大したことはありませんが、割とdateの扱いで苦労しています。

ASOCでは、dateオブジェクトの扱いがややめんどうで、current applicationへのtellブロック内でしか正常に機能しませんし、ハンドラ間でdateオブジェクトの受け渡しを行うのはエラーの元になります。

そんなわけで、dateオブジェクトを裸のままで扱わず、局所的にdateオブジェクトを生成しては必要な情報を取り出すという、かなりめんどうな取扱いを行っています。

かといって、NSDateやNSCalendarを使うのも……たった曜日の情報を欲しいだけなのにどれだけ記述させたら気がすむんだと呆れるほどのプログラムになってしまうので、見送りました。いいフレームワークがあれば使わないでもないですが、OSバージョンが上がるたびにメンテナンスする必要があることを考えると、ASのdateオブジェクトを使ったほうが、まだ手軽です。

→ Xcodeプロジェクトのダウンロード(82KB)

2013/09/04 指定月のカレンダーを1D List(7 days x 6 weeks) で返す

指定月のカレンダーを1次元配列のリスト型変数に文字で格納するAppleScriptです。

カレンダーは7曜日×最大で6週になります(土曜日から始まる31日の月とか)ので、7×6=42の要素からなる1D Listを作成しています。

cal10.png

AppleScript名:指定月のカレンダーを1D List(7 days x 6 weeks) で返す
set tYear to 2013
set tMonth to 9

set aCalList to retListCalendar(tYear, tMonth) of me
–> {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "", "", "", "", "", "", "", "", "", "", "", ""}

–指定月のカレンダーを1D List(7 days x 6 weeks) で返す
on retListCalendar(tYear, tMonth)
  
  
set mLen to getMlenInternational(tYear, tMonth) of me
  
set aList to {}
  
  
set fDat to retDateOwithParam(tYear, tMonth, 1, 0, 0, 0) of me
  
tell current application
    set aOffset to (weekday of fDat) as number
  end tell
  
  
–header gap
  
repeat (aOffset - 1) times
    set the end of aList to ""
  end repeat
  
  
–calendar body
  
repeat with i from 1 to mLen
    set the end of aList to (i as string)
  end repeat
  
  
–footer gap
  
repeat (42 - aOffset - mLen + 1) times
    set the end of aList to ""
  end repeat
  
  
return aList
  
end retListCalendar

on getMlenInternational(aYear, aMonth)
  
  
set sDat to retDateOwithParam(aYear, aMonth, 1, 0, 0, 0) of me
  
  
if aMonth is not equal to 12 then
    set eDat to retDateOwithParam(aYear, aMonth + 1, 1, 0, 0, 0) of me
  else
    set eDat to retDateOwithParam(aYear + 1, 1, 1, 0, 0, 0) of me –2015/2/1改修
  end if
  
  
set eDat to eDat - 1
  
set mLen to day of eDat
  
  
return mLen
  
end getMlenInternational

–国際化対応 パラメータによるdateオブジェクト作成ルーチン
on retDateOwithParam(yearNum, monthNum, dateNum, hourNum, minuteNum, secondNum)
  tell current application
    set aDateO to current date
    
    
set year of aDateO to yearNum
    
set month of aDateO to monthNum
    
set day of aDateO to dateNum
    
set hours of aDateO to hourNum
    
set minutes of aDateO to minuteNum
    
set seconds of aDateO to secondNum
    
    
return aDateO
  end tell
end retDateOwithParam

★Click Here to Open This Script 

2013/09/04 国際化対応mLen

指定の月の長さ(日数)を求めるmLenの、国際化対応バージョンです。

年、月を指定すると、該当月の日数を返します。

→ 本ルーチンにはバグが発見されたため、v2を使ってください(2015/2/1)。

スクリプト名:国際化対応mLen
set mLen to getMlenInternational(2013, 9) of me
–> 30

on getMlenInternational(aYear, aMonth)
  
  
set sDat to retDateOwithParam(aYear, aMonth, 1, 0, 0, 0) of me
  
  
if aMonth is not equal to 12 then
    set eDat to retDateOwithParam(aYear, aMonth + 1, 1, 0, 0, 0) of me
  else
    set eDat to retDateOwithParam(aYear, 1, 1, 0, 0, 0) of me
  end if
  
  
set eDat to eDat - 1
  
set mLen to day of eDat
  
  
return mLen
  
end getMlenInternational

–国際化対応 パラメータによるdateオブジェクト作成ルーチン
on retDateOwithParam(yearNum, monthNum, dateNum, hourNum, minuteNum, secondNum)
  set aDateO to current date
  
  
set year of aDateO to yearNum
  
set month of aDateO to monthNum
  
set day of aDateO to dateNum
  
set hours of aDateO to hourNum
  
set minutes of aDateO to minuteNum
  
set seconds of aDateO to secondNum
  
  
return aDateO
  
end retDateOwithParam

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/04/25 年代のデータから、{開始年, 終了年} のリストを作成 v2

生まれた年を10年刻みの「年代」別にとらえてデータ集計を行いたいときに、どの年代別の集計を行いたいかをリストで与えておくと、その実際の「開始年」「終了年」のリストを作成してくれるAppleScriptです。

元データは、1950年代、1960年代、1970年代……というリストのデータにしておいて、

  set condList to {1950, 1960, 1970, 1980, 1990, 2000, 2010}

そこから厳密な開始年,終了年を求めます。

  –> {{0, 1959}, {1960, 1969}, {1970, 1979}, {1980, 1989}, {1990, 1999}, {2000, 2009}, {2010, 2019}}

最初のアイテムだけはそれ以前(1940年代とか1930年代とか)のデータの受け皿とするために、開始年を0年に設定しています。

10年刻みだとか、そういう暗黙の「お約束」をそのままコーディングしていますが、条件として与えられた最初のリストから、分析するようにすべきでしょう。

昔は、データ集計といえば(Classic Mac OSの頃はOSの安定性もイマイチだったので)安全のためにFileMaker Proを外部からAppleScriptでコントロールして集計を行うことが(個人的に)多かったのですが、Mac OS XになってOSの安定性とかソートライブラリの量が昔とは比較にならないほど向上したため、ほとんどAppleScriptだけで行うようになりました。

あるいは、FileMaker Proからデータを取り出して、あとはひたすらAppleScriptだけでデータの集計や抽出を行うとか。そういうデータ処理のために、こういう(他人から見ると謎な存在の)プログラムをコツコツ作っています。

スクリプト名:年代のデータから、{開始年, 終了年} のリストを作成 v2
set condList to {1950, 1960, 1970, 1980, 1990, 2000, 2010}
set conList to retStartEndCondition(condList) of me
–> {{0, 1959}, {1960, 1969}, {1970, 1979}, {1980, 1989}, {1990, 1999}, {2000, 2009}, {2010, 2019}}

–年代のデータから、{開始年, 終了年} のリストを作成
on retStartEndCondition(condList)
  
  
set newConList to {}
  
  
set firstF to true
  
repeat with i in condList
    
    
if firstF = true then
      set startNum to 0
      
set endNum to (contents of i) + 9
      
set firstF to false
    else
      set startNum to contents of i
      
set endNum to i + 9
    end if
    
    
set the end of newConList to {startNum, endNum}
    
  end repeat
  
  
newConList
  
end retStartEndCondition

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/04/18 24時間以上の時間を指定されることを前提として時刻および日付を解釈してdateオブジェクトを返す

日付文字列(YYYY/MM/DD)と時刻の文字列(hh:mm:ss)からdateオブジェクトを作成するAppleScriptです。dateオブジェクトに変換するさい、28時などの24時を超える表記を考慮して日付計算に反映しています。

OS X 10.8のdateオブジェクトのバグ(日本語環境で発生)の影響は受けていません(OS X 10.8.3上にて検証)。

スクリプト名:24時間以上の時間を指定されることを前提として時刻および日付を解釈してdateオブジェクトを返す
set aTime to "28:00:00"
set aDate to "2013/04/19"

set aDateObj to retDateObj(aDate, aTime) of me
–> date "2013年4月20日土曜日 4:00:00"

–24時間以上の時間を指定されることを前提として時刻および日付を解釈してdateオブジェクトを返す
on retDateObj(aDate, aTime)
  
  
set hList to parseByDelim(aTime, ":") of me
  
set hNum to (contents of first item of hList) as number
  
set dPlus to hNum div 24 –日付の繰り上がり分
  
set hNew to (hNum mod 24) as string
  
  
set first item of hList to hNew
  
set newTime to retConcatText(hList, ":") of me
  
  
set newDateStr to aDate & " " & newTime
  
set newDateObj to (date newDateStr) + dPlus * days
  
  
return newDateObj
  
end retDateObj

–与えられた文字列を、指定デリミタ文字でparseしてリストにして返す
on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

–リストを任意のデリミタ付きでテキストに
on retConcatText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retConcatText

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/04/06 開始日と終了日の間を、指定日数単位で切った{開始日,終了日}のリストの日付文字列リストを返す

開始日と終了日(サンプルでは当日の日付)の間を、指定日数単位(サンプルでは7日)で区切った、{開始日,終了日}のリストの日付文字列リストを返すAppleScriptです。

本ScriptはOS X 10.8特有のdateバグの影響は受けていません。

スクリプト名:開始日と終了日の間を、指定日数単位で切った{開始日,終了日}のリストの日付文字列リストを返す
set aDate to “2013/2/5″
set aDateObj to date aDate

set curDate to current date

set bList to makeFromToDateStrList(aDateObj, curDate, 7, “/”) of me

–> {{”2013/02/05″, “2013/02/11″}, {”2013/02/12″, “2013/02/18″}, {”2013/02/19″, “2013/02/25″}, {”2013/02/26″, “2013/03/04″}, {”2013/03/05″, “2013/03/11″}, {”2013/03/12″, “2013/03/18″}, {”2013/03/19″, “2013/03/25″}, {”2013/03/26″, “2013/04/01″}, {”2013/04/02″, “2013/04/08″}}

–開始日と終了日の間を、指定日数単位で切った{開始日,終了日}のリストの日付文字列リストを返す
on makeFromToDateStrList(fromDate, toDate, stepDateNum, aParseStr)
  
  
set aList to {}
  
  
repeat while fromDate < toDate
    set date1 to retDateStr(fromDate, aParseStr) of me
    
set date2 to retDateStr(fromDate + ((stepDateNum - 1) * days), aParseStr) of me
    
    
set the end of aList to {date1, date2}
    
set fromDate to fromDate + stepDateNum * days
  end repeat
  
  
return aList
  
end makeFromToDateStrList

–”YYYY-MM-DD” を返す
on retDateStr(aDate, aSep)
  
  
set aYear to year of aDate
  
set aMonth to month of aDate as number
  
set aDay to day of aDate
  
  
set yStr to retZeroPaddingText(aYear, 4) of me
  
set mStr to retZeroPaddingText(aMonth, 2) of me
  
set dStr to retZeroPaddingText(aDay, 2) of me
  
  
set resStr to yStr & aSep & mStr & aSep & dStr
  
  
return resStr
  
end retDateStr

–数値にゼロパディングしたテキストを返す
on retZeroPaddingText(aNum, aLen)
  
  
set tText to (“0000000000″ & aNum as text)
  
set tCount to length of tText
  
set resText to text (tCount - aLen + 1) thru tCount of tText
  
  
return resText
  
end retZeroPaddingText

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/03/27 自然言語による相対日付指定v14

2013/03/26 10.8でdate文のトリッキーな記述を回避する

「OS X 10.8のdateに強烈なバグ」の話の続報です。

OS X 10.8になって正常に動作しなくなった「自然言語による相対日付指定v13」サブルーチンの調査中に出くわした不具合点とその回避方法について解説します。

結論からいえば、date文のトリッキーな記述を行っていた箇所があり、そこが問題になっていました。素直に書くようにすれば、機能を回復できます。

他のCJK言語環境(中国語や韓国語)においても問題が発生するのか興味深いところです。

スクリプト名:10.8でdate文のトリッキーな記述を回避する
–10.8で問題になる書き方
set tmp4 to "2013/2/1"
set ret2Date to date "0:0:0" of (date tmp4)
–> date "1999年12月31日金曜日 0:00:00"

–10.8で問題にならない書き方
set tmp4 to "2013/2/1"
set ret2Date to date (tmp4 & " 0:0:0")
–> date "2013年2月1日金曜日 0:00:00"

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/03/25 OS X 10.8のdateに強烈なバグ

10.8になって、「自然言語による相対日付指定v13」などの高度な処理を行うカレンダー計算プログラムが正しい値を返さなくなったことに気付いていたのですが、これがあまりに巨大なプログラムなので、問題の所在がどこにあるのか調査できずにいました。

確認してみたところ、どうやらOS X 10.8のdate文に強烈なバグが存在していることが分りました。確認はOS X 10.8.3(Build 12D78)にて行っています。

スクリプト名:10.8のdateバグ
set a to “2013年2月1日金曜日 0:00:00″
set b to date a
–> date “1999年12月31日金曜日 0:00:00″

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

date文で曜日が書かれた日付テキストをdateオブジェクトに変換すると、すべて「1999年12月31日金曜日 0:00:00」になってしまうというものです。

さらに、AppleScriptエディタ上でdate文のあとにダイレクトに日付文字列を書いて指定し、コンパイル(構文確認)を行うとあからさまに1999年12月の日付に変わってしまいます。

ase11.png
▲文字入力中。このあと、コンパイル(構文確認)を実行すると……

ase21.png
▲1999年12月の日付に勝手に書き換えられてしまう!

念のため、手元のMac OS X 10.6.8および10.7.5の環境で同様の内容をテストしてみましたが、これらの環境では問題は発生していません。

問題の回避策は、

 (1)dateに与える日付文字列に曜日を含めないこと
 (2)current dateでdateオブジェクトを作成しておいて、そのyear, month, dayなどのプロパティを個別に設定して返すサブルーチンを用いること
 (3)dateに与える日付文字列に日本語の文字列を含めないこと
 (4)曜日の文字列だけ英語で書くこと

などが考えられます。

スクリプト名:10.8のバグの一時的な回避策1
set a to “2013年2月1日” –曜日を含めない
set b to date a
–> date “2013年2月1日金曜日 0:00:00″

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

スクリプト名:10.8のバグの一時的な回避策2
set aDate to makeDateObj(2013, 2, 1, 0) of me
–> date “2013年2月1日金曜日 0:00:00″

on makeDateObj(aYear, aMonth, aDay, aTimeNum)
  set a to current date
  
set year of a to (aYear as number)
  
set month of a to (aMonth as number)
  
set day of a to (aDay as number)
  
set time of a to aTimeNum
  
return a
end makeDateObj

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

スクリプト名:10.8のバグの一時的な回避策3
set a to “2013/2/1 0:00:00″ –日本語の日付文字列を渡さない
set b to date a
–> date “2013年2月1日金曜日 0:00:00″

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

スクリプト名:10.8のバグの一時的な回避策4
set a to “2013年2月15日Friday” –曜日だけ英語で書く
set b to date a
–> date “2013年2月15日金曜日 0:00:00″

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/03/04 指定日時の午前午後を返す

指定の日時(dateオブジェクト)から午前/午後を返すAppleScriptです。

……というよりも、AppleScriptにそんな機能はないので、dateオブジェクトから「時」を数値で取得して、条件文で判定するということになります。

AppleScript名:指定日時の午前午後を返す_10.10
set aDate to current date –現時刻
set ampmRes to retAMPM(aDate) of me

–指定日時の午前/午後を返す
on retAMPM(aDate as date)
  set a to hours of aDate –「時」を取得
  
  
if a 0 and a < 12 then
    return "AM"
  else
    return "PM"
  end if
  
end retAMPM

★Click Here to Open This Script 

2012/06/16 インターネットのサービスを利用して日本国内の明日の天気予報を取得する

Livedoorの「お天気Webサービス」を呼び出して、日本国内の天気予報を取得するAppleScriptの改良(?)版です。構文確認(コンパイル)および実行には、仏Satimage SoftwareのフリーのOSAX「XMLLib OSAX」を必要とします。

# 「コンパイル」という言葉にだまされてか、AppleScriptのことを「インタプリタ型言語ではない」と勘違いしている人がたまにいますが、AppleScriptは逐次実行型のインタプリタ型言語です(内部で中間コードに置き換えることをコンパイルと呼んでいるだけです)

天気予報を取得して、その対象日付を求めます(最初のバージョンもここまでやっていました)。

問題はこの日付の文字列フォーマットがそのままではAppleScriptのdateオブジェクトに変換できなかったので……Googleで検索したら、あっさり海外(ドイツ?)で見つかりました。得られた文字列をdateオブジェクトに変換して、日付情報を取得。天気予報日付がcurrent dateの翌日になっていることを確認して値を返します。

明確に「明日」の天気予報を求めるように試してみましたが……はたしてどうでしょう?(これ、あんまりテストしていないもので、、、)

→ このバージョンのAPIが廃止になったので、REST APIを呼び出すように変更しています

スクリプト名:インターネットのサービスを利用して日本国内の明日の天気予報を取得する
–東京の明日の天気を求める
set aRec to getTomorrowWeatherForecast(63) of me –東京

–>
(*
{title:”東京都 東京 - 明日の天気”, yohouDate:”Sun, 17 Jun 2012 00:00:00 +0900″, yohouSakuseiDate:”Sat, 16 Jun 2012 17:00:00 +0900″, yohou:”雨のち曇”, descText:”東京地方と伊豆諸島では、明日昼前にかけて竜巻などの激しい突風、急な強い雨、落雷に注意して下さい。また、伊豆諸島では、強風や高波、濃霧による視程障害に注…
[PR]きょうは洗濯できるかな?“}

*)

on getTomorrowWeatherForecast(cityCode)
  set aDate to current date
  
set aDateNum to day of aDate
  
set dList to {“today”, “tomorrow”}
  
  
repeat with i in dList
    set j to contents of i
    
    
set aRes to getWeatherForecast(cityCode, j) of me
    
set yStr1 to yohouDate of aRes
    
set yStr2 to yohouSakuseiDate of aRes
    
    
set yObj1 to parse_RFC2822_date_string(yStr1) of me –予報対象日付
    
set yObj2 to parse_RFC2822_date_string(yStr2) of me –予報作成日付
    
    
set bDate to day of yObj1
    
    
if aDateNum + 1 = bDate then
      return aRes
    end if
  end repeat
  
  
return false
  
end getTomorrowWeatherForecast

–インターネットのサービスを利用して日本国内の天気予報を取得する
on getWeatherForecast(cityCode, relativeDateString)
  
  
set aURL to “http://weather.livedoor.com/forecast/webservice/rest/v1?” –Livedoor Weather Forecast Service
  
set aCity to (“city=” & cityCode as string) & “&”
  
set aDay to “day=” & relativeDateString
  
  
set allURL to aURL & aCity & aDay
  
  
set XMLbody to XMLOpen allURL
  
set the_root to XMLRoot XMLbody
  
  
set res1 to contents of first item of (XMLGetText (XMLXPath the_root with “/lwws/title”))
  
set res2 to contents of first item of (XMLGetText (XMLXPath the_root with “/lwws/forecastdate”))
  
set res3 to contents of first item of (XMLGetText (XMLXPath the_root with “/lwws/publictime”))
  
set res4 to contents of first item of (XMLGetText (XMLXPath the_root with “/lwws/telop”))
  
set res5 to contents of first item of (XMLGetText (XMLXPath the_root with “/lwws/description”))
  
  
set wRec to {title:res1, yohouDate:res2, yohouSakuseiDate:res3, yohou:res4, descText:res5}
  
  
return wRec
  
end getWeatherForecast

–RFC2022形式の日付文字列をdateオブジェクトに
on parse_RFC2822_date_string(ts)
  –引用元:
  
–http://www.j-schell.de/node/121
  
  
– parses a date string using PHP strtotime.
  
– Returns an AppleScript date
  
– Time is in your local time zone
  
–limits:
  
–19. Jan 2038 03:14:07 UTC
  
–13. Dec 1901 20:45:52 UTC
  
  
set php_cmd to “php -r “
  
set php_script to ?
    “$x = @strtotime($argv[1]);
    if ($x === false)
      print \”error\”;
    else
      print (@date ( \”Y-n-j-G-i-s\”, $x ));”
  set php_script to quoted form of php_script
  
set php_arg to quoted form of ts
  
  
set sh_script to php_cmd & php_script & ” “ & php_arg
  
–log sh_script
  
  
set dt to (do shell script sh_script)
  
  
– let us throw an error if parsing went wrong
  
– change the if line if you need something else
  
– return false
  
– may be an alternative if you want to react on problems
  
– without a try … on error block.
  
if dt = “error” then
    error “Handler parse_date_string could not parse string “” & ts & “”” number -30720
  end if
  
set the_date to current date
  
set day of the_date to 1
  
set {year of the_date, month of the_date, day of the_date, hours of the_date, minutes of the_date, seconds of the_date} to every word of dt
  
return the_date
end parse_RFC2822_date_string

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2012/02/25 自然言語による相対日付指定v13

2011/02/21 「m月d日」の文字列を「m/d」に変換して返す

「m月d日」のフォーマットの文字列を「m/d」に変換して返すAppleScriptです。

Mac OS X 10.6上で作成してあとから10.4.11上でも動くように対応したものです。まー、この手の簡単なテキスト整形サブルーチンは大量に生々しいものがゴロゴロしていますが、このぐらいのあたりさわりのないものしか出せないような気が、、、、

スクリプト名:「m月d日」の文字列を「m/d」に変換して返す
set aStr to "11月1日"
set aRes to retMonthSlashDateStr(aStr) of me
–> "11/1"

–「m月d日」の文字列を「m/d」に変換して返す
on retMonthSlashDateStr(aStr)
  set {mStr, dStr} to retMonthStrAndDateStr(aStr, {"月", "日"}, 2) of me
  
set resStr to mStr & "/" & dStr
  
return resStr
end retMonthSlashDateStr

–指定リストを指定デリミタでparseして日付文字列をリストにして、先頭から指定アイテムまで取り出して返す
–ただし、日付など「月」「日」が必ず存在しているという前提条件が成立するものだけが処理対象
on retMonthStrAndDateStr(aStr, delimiterList, lastItem)
  set osVer to system attribute "sys2"
  
  
if osVer 5 then
    –Mac OS X 10.5以上の場合
    
set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to delimiterList
    
set aList to text items of aStr
    
set AppleScript’s text item delimiters to curDelim
    
set bList to items 1 thru lastItem of aList
    
return bList
    
  else
    –Mac OS X 10.4以下の場合
    
set resList to {}
    
    
repeat with i in delimiterList
      set curDelim to AppleScript’s text item delimiters
      
set AppleScript’s text item delimiters to i –10.4ではデリミタをリストで指定できないので1つずつ指定
      
set aList to text items of aStr
      
set AppleScript’s text item delimiters to curDelim
      
      
set the end of resList to item 1 of aList
      
      
try
        set aStr to contents of (item 2 of aList) –ここ、あんまりよくないな〜。実害はないけど、美しくない
      end try
      
    end repeat
    
    
return resList
  end if
  
end retMonthStrAndDateStr

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/02/06 指定年のすべての日付をdateオブジェクトで取得する

指定年のすべての日付をdateオブジェクトで取得するAppleScriptです。

こういう基礎的なプログラムは、誰が組んでもあんまり差が出ないので、あえてゼロから組む必要性がなく……こうした基礎的な部品を組み合わせてどれだけ高度な処理を組み上げられるか、というところに頭を使いたいところです。

スクリプト名:指定年のすべての日付をdateオブジェクトで取得する
set thisYear to 2020
set dList to {}

repeat with i from 1 to 12
  set mLen to getMlen(thisYear, i) of me
  
repeat with ii from 1 to mLen
    set dStr to (thisYear as string) & "/" & (i as string) & "/" & (ii as string)
    
set the end of dList to date dStr
  end repeat
end repeat

dList

–指定月の長さを得る(日数)
on getMlen(aYear, aMonth)
  
  
set aDat to (aYear as text) & "/" & (aMonth as text) & "/1"
  
if aMonth is not equal to 12 then
    set eDat to ((aYear as text) & "/" & (aMonth + 1) as text) & "/1"
  else
    set eDat to ((aYear + 1) as text) & "/" & (1 as text) & "/1"
  end if
  
  
–set sDat to date aDat
  
set eDat to date eDat
  
set eDat to eDat - 1
  
  
set mLen to day of eDat
  
return mLen
  
end getMlen

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/12 与えられたリストに、値がヌルの要素が入っているか判定し、フラグ、ブランク開始終了位置を返す v2

与えられたリストに、値がヌルの要素が入っているか判定し、ヌルが入っているかをフラグで返し、前方にブランクがあるか後方にブランクがあるかのフラグ、ブランク開始位置、ブランク終了位置を返すAppleScriptです。

何らかの数字をO、ブランクをXとすると……

後方にブランクが存在するリスト {O, O, O, O, O, X, X}
前方にブランクが存在するリスト {X, X, O, O, O, O, O}

というタイプの「前方か後方にブランクが存在するリスト」を処理対象にしています。途中にブランクが登場するようなもの(例:{O, X, O, O, X, O, O})は前提にしていません。

はっきり言えば、カレンダーの日付の存在箇所と存在しない箇所をピックアップするために作成したものなので、そういう用途に使いました。

スクリプト名:与えられたリストに、値がヌルの要素が入っているか判定し、フラグ、ブランク開始終了位置を返す v2
set aList to {“1″, “2″, “3″, “4″, “5″, “6″, “7″} –すべての要素がヌルではないリスト
set {aFlag, pFlag, bStart, bEnd} to detectBlankItemFromList(aList) of me
log {aFlag, pFlag, bStart, bEnd}
–> (*true, , 0, 0*)

set aList to {“1″, “2″, “3″, “”, “”, “”, “”} –後ろにヌルが入っているリスト
set {aFlag, pFlag, bStart, bEnd} to detectBlankItemFromList(aList) of me
log {aFlag, pFlag, bStart, bEnd}
–> (*false, after, 4, 7*)

set aList to {“”, “”, “”, “4″, “5″, “6″, “7″} –先頭にヌルが入っているリスト
set {aFlag, pFlag, bStart, bEnd} to detectBlankItemFromList(aList) of me
log {aFlag, pFlag, bStart, bEnd}
–> (*false, before, 1, 3*)

–与えられたリストに、値がヌルの要素が入っているか判定し、フラグ、前がブランクか後がブランクか、ブランク開始・終了位置を返す
on detectBlankItemFromList(aList)
  set aCount to 1
  
set retF to true
  
set aLen to length of aList
  
  
set directionF to “”
  
  
set blankStart to 1
  
set blankEnd to aLen
  
  
  
if contents of item 1 of aList = “” then
    –頭の方にブランクがある場合
    
set rList to reverse of aList –リストを逆順に
    
repeat with i in rList
      if contents of i is equal to “” then
        set retF to false –Blank Itemが入っている場合
        
exit repeat
      end if
      
set aCount to aCount + 1
    end repeat
    
    
set blankStart to 1
    
set blankEnd to (aLen - aCount + 1)
    
    
set directionF to “before”
    
  else if contents of last item of aList = “” then
    –末尾の方にブランクがある場合
    
repeat with i in aList
      if contents of i is equal to “” then
        set retF to false –Blank Itemが入っている場合
        
exit repeat
      end if
      
set aCount to aCount + 1
    end repeat
    
    
set blankStart to aCount
    
set blankEnd to aLen
    
    
set directionF to “after”
    
  else
    –先頭にも末尾にもブランクがない場合
    
set blankStart to 0
    
set blankEnd to 0
    
set retF to true
    
  end if
  
  
return {retF, directionF, blankStart, blankEnd}
  
end detectBlankItemFromList

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2011/01/12 指定日がその月の中で何週目かを求めて、週リストを取得する

指定日がその月の中で何週目かを求め、その該当週のdateオブジェクトが入ったリストを取得するAppleScriptです。

スクリプト名:指定日がその月の中で何週目かを求めて、週リストを取得する
set tDate to "2011/1/3"
set tDateObj to date tDate

set aWeek to retTheNumberOfWeekInTheMonth(tDateObj) of me
–> 2

set aList to retTheListOfWeekInTheMonth(tDateObj, aWeek) of me
–> {date "2011年1月2日日曜日 0:00:00", date "2011年1月3日月曜日 0:00:00", date "2011年1月4日火曜日 0:00:00", date "2011年1月5日水曜日 0:00:00", date "2011年1月6日木曜日 0:00:00", date "2011年1月7日金曜日 0:00:00", date "2011年1月8日土曜日 0:00:00"}

–指定日が所属する月の中の指定週のリストを求める
on retTheListOfWeekInTheMonth(tDateObj, theWeek)
  –引数から年と月を求める
  
set theYear to year of tDateObj
  
set theMonth to month of tDateObj as number
  
set theDate to day of tDateObj
  
  
–指定月のリストを作成
  
set mList to makeMonthList(theYear, theMonth) of me
  
  
–得られた週リストから、指定週のリストを返す
  
set wList to contents of item theWeek of mList
  
return wList
  
end retTheListOfWeekInTheMonth

–指定日がその月の中で何週目かを求める
on retTheNumberOfWeekInTheMonth(tDateObj)
  –引数から年と月を求める
  
set theYear to year of tDateObj
  
set theMonth to month of tDateObj as number
  
set theDate to day of tDateObj
  
  
–指定月のリストを作成
  
set mList to makeMonthList(theYear, theMonth) of me
  
  
set wNum to getWeekNumInTheMonth(mList, tDateObj) of me
  
  
return wNum
  
end retTheNumberOfWeekInTheMonth

–指定のカレンダーから、指定日が何週目かを求める
on getWeekNumInTheMonth(yList, aDate)
  set weekCount to 1
  
  
repeat with i in yList
    repeat with ii in i
      set jj to contents of ii
      
if jj is equal to aDate then
        return weekCount
      end if
    end repeat
    
set weekCount to weekCount + 1
  end repeat
  
return 0
end getWeekNumInTheMonth

–指定の月を1月分リスト化
on makeMonthList(theYear, theMonth)
  
  
set yList to {}
  
set curList to {}
  
  
set curList to {"", "", "", "", "", "", ""}
  
  
–1か月分の日をリスト化
  
set aLen to getMlen(theYear, theMonth) of me
  
  
repeat with ii from 1 to aLen
    set aDateStr to (((theYear as string) & "/" & theMonth as string) & "/" & ii as string)
    
set aDate to date aDateStr
    
set aWD to weekday of aDate as number
    
set item aWD of curList to aDate
    
if aWD = 7 then
      set the end of yList to curList
      
set curList to {"", "", "", "", "", "", ""}
    end if
  end repeat
  
  
if curList is not equal to {"", "", "", "", "", "", ""} then
    set the end of yList to curList
  end if
  
  
return yList
  
end makeMonthList

–指定月の長さを得る(日数)
on getMlen(aYear, aMonth)
  
  
set aDat to (aYear as text) & "/" & (aMonth as text) & "/1"
  
if aMonth is not equal to 12 then
    set eDat to ((aYear as text) & "/" & (aMonth + 1) as text) & "/1"
  else
    set eDat to ((aYear + 1) as text) & "/" & (1 as text) & "/1"
  end if
  
  
–set sDat to date aDat
  
set eDat to date eDat
  
set eDat to eDat - 1
  
  
set mLen to day of eDat
  
return mLen
  
end getMlen

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に