時・分・秒の扱い

time属性の値を加工する

 日付の値の属性には時・分・秒は用意されていません。
 これらの値を取り出すには、その日の0時からの積算秒数(秒を全部足したもの)を表す属性のtimeを使います。
 このあたりの計算を分かりやすくするために、幾つかの定義済み変数が用意されていますので、それらを有効に使います。
 まずは時間を求めるハンドラです。
 hours(3600)で割って余りを捨てれば時間が求まります。

getHour(current date)

on getHour(theDate)
	(time of theDate) div hours
end getHour

 次は秒を求めるハンドラです。
 minutes(60)で割った余りが現在の秒数です。

getSecond(current date)

on getSecond(theDate)
	(time of theDate) mod minutes
end getSecond

 最後に分を求めるハンドラです。
 まず、hours(3600)で割った余りの秒数を求め、それをminutes(60)で割って余りを捨てるというわけです。

getMinuit(current date)

on getMinuit(theDate)
	((time of (theDate)) mod hours) div minutes
end getMinuit

時刻属性を設定

 今度は逆に時刻を日付の値に設定する方法です。
 次のハンドラは時間を設定し分と秒を0にします。
 これは簡単でtime属性に、時間にhours(3600)をかけたものを設定するだけです。

setHour of (current date) to 5

on setHour of theDate to theHour
	set time of theDate to theHour * hours
	return theDate
end setHour

 今度は逆に時刻を日付の値に設定する方法です。
 次のハンドラは秒を設定します。
 積算分数を求めて、それにminutes(60)をかけることで秒以下を切り捨てます。さらに秒を足せばできあがりです。

setSecond of (current date) to 5

on setSecond of theDate to theSec
	set time of theDate to ((time of theDate) div minutes) * minutes + theSec
	return theDate
end setSecond

 次のハンドラは時間はそのままで分を設定し秒を0にします。
 先ほど紹介した方法を使って時間を求めて、それにhours(3600)をかけることで時間以下を切り捨てます。さらに分を足せばできあがりです。

setMinuit of (current date) to 30

on setMinuit of theDate to theMin
	set time of theDate to ((time of theDate) div hours) * hours + theMin * minutes
	return theDate
end setMinuit

日付属性の設定方法」で紹介している、まとめて属性を設定(その2)の方法を使う手もあります。
 日付の書式と違って、時刻の書式はコントロールパネルの設定によらない(たぶん)ので、別環境で使うスクリプトにも使えるんじゃ無いかと思いますが自信無し。

日付どうしの引き算

 二つの日付の差を秒数で得ることもできます。
「日付1-日付2」で、日付の間の秒数が求まります。
 以下は、選択したファイルが、現在の日付から何秒前に変更されているかを求めます。

set theFile to (choose file)
tell application "Finder"
	set theDifference to (current date) - (modification date of theFile)
end tell
display dialog ((theDifference as string) & "秒前に変更されています")

 秒数だと、ピンとこないので、何日と何秒前かを求めます。
 何日分の秒数に当るかは、時間を求める場合と同じようにして、定義済み変数のdays(86400)を使います。

秒数 div days

で、OKです。
 ちなみに、weeks(604800)という定義済み変数もありますから、何週間かを求めることも簡単です。

秒数 div weeks

 以下のスクリプトは、入力した秒数を日数とあまりの秒数に変換して教えます。

set theSec to text returned of (display dialog "計算する秒数を入力して下さい" default answer "0")
set theDay to theSec div days
set theTime to theSec mod days
display dialog (theSec & "秒は、" & theDay & "日と、あまり" & theTime & "秒です") as string

 ここで求められた。あまりの秒数はつまるところ積算秒数なので、後は既にやった方法を使って、時間や分を求めることもできます。

時間の足し引き

 日付に整数を足したり引いたりして、日付からn秒前、または後の日付を得ることができます。
 足したり引いたりするのは秒数だけしかできませんが、定義済み変数を利用すれば、時間や分、日、週を足したり引いたりするのも簡単です。

日付 + n(秒)

で、日付のn秒後の日付を得ることができます。逆に

日付 - n(秒)

で、日付のn秒前の日付を得ます。
 以下のスクリプトは、現在から4日後を求めます。

(current date) + 4 * days

 MacOS8.5以降ならば、delay命令が用意されていて、数秒処理を停止すると言うことも簡単にできるようになりました。
 ですが以前の環境でも、日付の足し算や引き算を使って、数秒処理を停止することもできます、以下は5秒停止するスクリプトです。

set theWait to (current date) + 5
repeat until (current date) > theWait
end repeat

アラームを作る

 以上を踏まえて、アラームを作ってみました。
 idleハンドラを利用する訳です。
 なんだかdateのテクニックと言うより、idolハンドラとかpropertyとかのテクニックの紹介のような気もしますけど。

property isSet : true
property nextSec : 1

set targetTime to text returned of (display dialog "何時に設定しますかh m sのスペース区切りの書式を使って下さい" & return & "例: 12 30 00" default answer "")

set curDate to current date
set targetDate to curDate
set time of targetDate to (word 1 of targetTime) * hours + (word 2 of targetTime) * minutes + (word 3 of targetTime)

-- 以下で属性を設定し、引数渡しの代わりに使う
-- idolは既に定義されているハンドラなので新しく引数を作れないため
set isSet to true -- フラグをセット
set nextSec to targetDate - curDate
if nextSec <= 0 then set nextSec to nextSec + days -- 既に過ぎている時刻だったら一日先にする

-- 起動時にidolが呼び出されるので、そのときにreturnにnextSecが設定される

on idle
	if isSet then
		set isSet to false
		return nextSec
	end if
	beep
	display dialog "時間です" buttons "OK" default button "OK"
	quit
end idle

 Tanaka's osaxのMT DateListを使えば、日付を数値か文字列のリストで得ることができます。MT Convert Dateで、文字列やリストから日付の値を得ることもできます。MT Timestampを使えば、文字列で"yymmddhhmmss"のタイムスタンプを得ることもできます。


2000-02-23 -2000-03-30