ラベル 日付 の投稿を表示しています。 すべての投稿を表示
ラベル 日付 の投稿を表示しています。 すべての投稿を表示

2014年8月21日木曜日

Thunderbird の日付をカスタマイズ - アドオン Super Date Format

1. 日付のフォーマットをカズタマイズ

SnapCrab_No-1378 Thunderbird の「送信日時」に「曜日」を表示するには、OS の日付フォーマットを変更する。日付のフォーマットをよりカスタマイズしたい場合、アドオン Super Date Format を利用する。

このアドオンはオプションに統合されている。 インストールすると、オプションの「表示」に

  • Date Format
  • Date Format Preferences

の 2 つのタブが表示される。

 

2. Super Date Format を有効にする

最初に Date Format Preferences タブにおいて、

  • Enable on Date column

にチェックをして、Thunderbird を再起動する。

    SnapCrab_No-1374

 

3. 日付フォーマットの書式

次に Data Format タブにおいて、表示をカスタマイズする。

例えば、以下のような日付のフォーマットにしたい。

SnapCrab_No-1379

Data Format タブの Date format:

%Y.%m.%d (%a) %p %I:%M

と入力する。

SnapCrab_No-1381

書式は以下の通り。

SnapCrab_No-1382

2014年8月20日水曜日

Thunderbird の「送信日時」に「曜日」を表示するには、OS の日付フォーマットを変更する - 「今日の曜日」も表示したい場合、アドオン ConfigDate を用いる。

1. 「送信日時」に「曜日」を表示したい

Thunderbird では「送信日時」に「曜日」が表示されない。

「曜日」があると、いつ来たメールか直感的に把握しやすくなる。日付でグループ化すると見やすくなるが、曜日も表示させたい。

SnapCrab_No-1370

この 「送信日時」は、Windows のタスクトレイに表示されている「日付」と「時刻」に対応している。

 

2. システムの「日付・時刻」フォーマットを変更する

日付のフォーマットを変更するには、

  • タスクトレイ上の「日付・時刻」の上で右クリック > 「日付と時刻の調整」

を選択。

SnapCrab_No-1371

「日付と時刻の変更」ボタンをクリック。

SnapCrab_No-1362

「カレンダーの設定の変更」をクリックする。

SnapCrab_No-1363

「日付(短い形式)」を

  • yy/MM/dd’(‘ddd’)’

に設定する

SnapCrab_No-1364

これにより、Thnderbird の「送信日時」に曜日が表示されるようになった。

SnapCrab_No-1367

 

3. ConfigDate で「今日の日付」に曜日を表示する

デフォルトでは、今日の送信日時には、「時刻」のみ表示される。もし、日付・曜日を表示したい場合、アドオン ConfigDate を用いる。

  • ConfigDate の設定より、日付 > 今日のメッセージ

において、「短い形式」または「曜日」を選択し、Thunderbird を再起動する。

SnapCrab_No-1373

 

関連記事

2010年11月8日月曜日

Haskell の日付型

Ruby, Python, Java の日付型

Java で日付型の値を扱う場合、何だかゴテゴテとしたコードを書く必要がある。これに対し、Ruby や Python の記述はシンプルでスッキリとしている。

例えば Ruby で `2010年4月1日’に対応した日付オブジェクトを使いたい場合、

require 'date'
puts Date.new(2010, 4, 1)

Python では、

import datetime
print datetime.date(2010, 4, 1)

ちなみに Java だと、

import java.util.Calendar;
import java.text.SimpleDateFormat;

public class TestDate {
    public static void main(String[] args){
	Calendar cal = Calendar.getInstance();
	cal.set(2010, Calendar.APRIL, 1);
	System.out.println
	    (new SimpleDateFormat
	     ("yyyy-MM-dd").format(cal.getTime()));
    }
}

うーん、ややこしい。 (+_+)

Java の日付時刻に関することは以下も参考に。

 

Data.Time

Haskell でも同じく Date 型がないかと探してみると、Data.Time の階層に日付を扱うためのモジュールがある。

の 4 つのモジュールに分かれており、上 3 つ はその名前通りの用途に用いることができそう。最後の LocalTiem モジュールの中には、日付を含まない時間を表す型が定義されていた。

(cf. 時刻を扱う - 特定の日付に属さない時間 )

 

日付から Day 型への変換

Data.Time.Calendar には日付に対応した Day 型が定義されている。

コンストラクタは、

ModifiedJulianDay {toModifiedJulianDay :: Integer} 

この型の説明には、

The Modified Julian Day is a standard count of days, with zero being the day 1858-11-17.

とある。 Modified Julian Day とは 「 ユリウス日(Julian Day)」 によると、

ユリウス日(ユリウス通日)とは紀元前4713年1月1日からの連続した通し番号の日数です。

ユリウス通日 – Wikipedia

数年にわたる2点の日数を計算するのに便利で、天文学年代学などで使われている。ユリウス通日では桁が多すぎるため、ユリウス通日から2400000.5を引いた修正ユリウス日(MJD)も広く使われている。

内部的にはこの数値が Day 型に使われているようだ。

 

fromGregorian 関数

日付からこの Day 型に変換するには、

fromGregorian :: Integer -> Int -> Int –> Day

この関数を使ってみる。

import Data.Time.Calendar
main = print $ fromGregorian 2010 4 1

 

toModifiedJulianDay 関数

fromGregorian 関数によって Day 型に変換された値は、セレクタ toModifiedJulianDay により修正ユリウス日を得られる。

フリーゲルの公式 によると、

例えば、2004年1月1日はy=2003、m=13、d=1なので

\lfloor 365.25 \times 2003 \rfloor + \lfloor 2003 / 400 \rfloor -  \lfloor 2003 / 100 \rfloor + \lfloor 30.59 ( 13 - 2 ) \rfloor + 1 - 678912
= 731595 + 5 − 20 + 336 + 1 − 678912 = 53005

となり、53005が修正ユリウス日となる。

確かめてみる。

Prelude> :m Data.Time.Calendar
Prelude Data.Time.Calendar> toModifiedJulianDay $ fromGregorian 2004 1 1
53005

 

グレゴリオ暦

それにしても Haskell では、Ruby や Python のようにシンプルに Date というような名前のコンストラクタではなく、fromGregorian というゴツイ関数名が付けられているのだろう?

Gregorian とは 「グレゴリオ暦」 のことを指し、

現在、日常使われているグレゴリオ暦は、1582年に制定された事実上の世界標準の暦です。 このグレゴリオ暦の前身はユリウス暦で、そのユリウス暦は、古代ローマ暦にエジプト 発祥の太陽暦を導入したものです。

日本では、1872年からグレゴリオ暦が採用されています。

普段意識せずに使っているのがグレゴリオ暦で、その前に使われていたのがユリウス暦だと。

なぜこの暦が使われるようになったかと言えば、グレゴリオ暦 - Wikipedia によると、

それまで用いられていたユリウス暦では、通常の年(平年)は1年を365日とし、4年に1回を閏年として366日とし、平均年を365.25日としていた。…

しかし太陽年は約365.2422日であるため、ユリウス暦の方式では1000年で約8日の誤差が生じる。これにより、比較的頻繁に補正することが必要であった。…

これに対して、新たに定められたグレゴリオ暦では、平年は1年を365日とし、4年に1回を閏年とするところまではユリウス暦と変わらないものの、さらに調整を加えて平均年を365.2425日とした。この調整とは「西暦紀元(西暦)の年数が100で割り切れてかつ400では割り切れない年は閏年としない[2]」というルールを加えることである。これはすなわち、ユリウス暦の方式では閏年とされる年であっても400年間に3回は閏年とせずに平年に戻すということである[3]

プログラムの入門書でよく見かける 「うるう年を判定するプログラム」 の判定の理屈は、このグレゴリオ暦に基いている。

ちなみに、2000年問題 – Wikipedia においても、

直接の原因は、プログラム内でを扱う際の年数の表現方法である。年数の表現をグレゴリオ暦の下二桁のみで行っている場合、2000年が内部で00年となり、これを1900年とみなしてしまい、例えば「データベースを日付順に並び替える処理をすると、順序が狂う」などの誤作動につながる可能性があるとされた。

また、現行の太陽暦であるグレゴリオ暦では

  1. 年が4で割り切れる年は閏年とする
  2. (1)のうち、年が100で割り切れる年は閏年としない
  3. (2)のうち、年が400で割り切れる年はこれを適用しない(つまり閏年とする)

というルールがあり、このため2000年は閏年だったが、誤って1と2のみを適用し、閏年としなかったプログラムが存在したため、この対応も併せて必要とされた。

 

他の言語における定義

Date - Rubyリファレンスマニュアル では、

new([year[, mon[, mday[, start]]]])

暦日付に相当する日付オブジェクトを生成します。

… 最後の引数は、グレゴリオ暦をつかい始めた日をあらわすユリウス日です。グレゴリオ暦の指定として真、ユリウス暦の指定として偽を与えることもできます。省略した場合は、Date::ITALY (1582年10月15日) になります。

Python の 6.10.3 date オブジェクト には、

日付は理想的なカレンダー、すなわち現在のグレゴリオ暦を過去と未来の両方向に無限に延長したもので表されます。 … この暦法は、全ての計算における基本カレンダーである、 … "予期的グレゴリオ (proleptic Gregorian)" 暦の定義に一致します。

Java の Calendar (Java Platform SE 6) における getInstance() メソッドにより返されるカレンダーオブジェクトを文字列表現にすると、

java.util.GregorianCalendar …

このクラスは GregorianCalendar (Java Platform SE 6) によると、

GregorianCalendar は、Calendar の具象サブクラスであり、世界のほとんどの地域で使用される標準的なカレンダシステムを提供します。 

GregorianCalendar は、グレゴリオ暦とユリウス暦をサポートするハイブリッドカレンダシステムで、単一の変わり目を処理します。

 

Data.Time の使用例

まずは Data.Time 関連のモジュールを読み込む。

Prelude> :m Data.Time
Prelude Data.Time>

Data/Time.hs を見てわかる通り、このモジュールで下位のモジュールがエクスポートされている。

 

日付の加算・減算

例えば、「2010年4月1日の 100 日後の日付」 を求めたい場合は、CalendaraddDays 関数を使い、

Prelude Data.Time> addDays 100 $ fromGregorian 2010 4 1
2010-07-10

「大晦日まで後何日か?」 求めたいなら diffDays 関数。

Prelude Data.Time> fromGregorian 2010 12 31 `diffDays` fromGregorian 2010 4 1
274

 

現在の日付・時刻は?

Ruby で現在の時刻を求める場合、

require 'date'
puts DateTime.now

同じように Haskell でも ClockgetCurrentTime 関数を使うと現在の時刻が表示される。

Prelude Data.Time> getCurrentTime
2010-11-08 03:09:48.769875 UTC

ただし、UTCTime 型の値が返される。この型の値は 協定世界時 – Wikipedia

協定世界時(きょうていせかいじ、UTC - Universal Time, Coordinated)とはセシウム原子時計が刻む国際原子時(TAI)をもとに、天文学的に決められる世界時(UT1)との差が1秒未満となるよう国際協定により人工的に維持されている世界共通の標準時である。…

世界各地の標準時はこれを基準として決めている。例えば、日本標準時は(JST)で協定世界時より9時間進んでおり、「+0900(JST)」のように表示する。

日本標準時を取得するには LocalTimegetZonedTime 関数を利用する。

Prelude Data.Time> getZonedTime
2010-11-08 12:10:21.06675 JST

 

LocalTime と ZonedTiem の関係

LocalTime 

A simple day and time aggregate, where the day is of the specified parameter, and the time is a TimeOfDay. Conversion of this (as local civil time) to UTC depends on the time zone.

LocalTime は日付と時刻を持つ型。これに TimeZone を加えると、世界標準の UTCTime になる。

タイムゾーンとは、

共通の標準時を使う地域全体を「等時帯」、「時間帯」または「タイムゾーン(time zone)」といい、その地域の標準時を示す際にはUTCとの差で示すことが多い。

(標準時 - Wikipedia)

例えば、日本は UTC + 9 で、この設定をする関数が hoursToTimeZone

localTimeToUTC 関数に TimeZone LocalTime 「2010年4月1日 6時0分0秒」 を与えて UTCTime を得る。

Prelude Data.Time> let tz = hoursToTimeZone 9
Prelude Data.Time> let lt = LocalTime (fromGregorian 2010 4 1) (TimeOfDay 6 0 0)
Prelude Data.Time> localTimeToUTC tz lt
2010-03-31 21:00:00 UTC

日本は UTC よりも 9 時間早いので、前日の 21 時となる。

 

現在からの日数を求める

先ほどと同様に、「現在の日付から 100 日後」 と、「現在から大晦日まで何日あるか」 を調べたい。

予め ZonedTime から日付と時刻に分解する補助的な関数を定義。

dayAndTime :: ZonedTime -> (Day, TimeOfDay)
dayAndTime zt = let lt = zonedTimeToLocalTime zt
                    day  = localDay lt
                    time = localTimeOfDay lt
                in (day, time)

day  = fst . dayAndTime
time = snd . dayAndTime

これを用いて、

main = do
-- 現在の時刻を取得 now <- getZonedTime -- 現在の日付から 100 日後は? print $ addDays 100 (day now) -- 現在から大晦日までは何日? print $ fromGregorian 2010 12 31 `diffDays` (day now)

 

後何分?

「現在の時刻から、特定の時刻まで後どれくらの時間があるか」 を調べたい。

時刻 t1 から t2 までの長さを求める diffTime を定義。

diffTime :: TimeOfDay -> TimeOfDay -> TimeOfDay
diffTime t1 t2 = timeToTimeOfDay 
                 (timeOfDayToTime t2 - timeOfDayToTime t1)

これを使い 「今から 22 時までの時間」 を求める例。

print $ diffTime (time now) (TimeOfDay 22 0 0) 

 

フォーマット

日付 `2010-04-01’ の表示を変更して `2010—04—01’ のような書式にしたい。

予め System.Locale をインポートしておき、defaultTimeLocale 関数を使えるようにしておく。

import System.Locale

formatTime 関数を使い、

print $ formatTime defaultTimeLocale "%Y--%m--%d" 
          $ fromGregorian 2010 4 1

 

全体のコード

関連記事

2009年9月18日金曜日

JavaScript で Blogger の「前の投稿」へのリンクを生成

Blogger の画面右下にある「前の投稿」へのリンクを作りたい。

 

どうするか?

今トップページの一番下にある記事の下にある「前の投稿」のリンクを見ると、

http://jutememo.blogspot.com/search?updated-max=2009-09-11T08%3A40%3A00%2B09%3A00&max-results=5

文字エンコードされているように見えるので、 decodeURIComponent – MDC を使いデコード。

decodeURIComponent("http://jutememo.blogspot.com/search?updated-max=2009-09-11T08%3A40%3A00%2B09%3A00&max-results=5")

結果は、

http://jutememo.blogspot.com/search?updated-max=2009-09-11T08:40:00+09:00&max-results=5

パラメータを見ると、

  • updated-max
  • max-results

updated-max は指定した日付と時間よりも前の記事を指定しており、max-results は 1 ページに表示する記事の数を表わしているようだ。

 

方法

日付の操作は Date – MDC を参照。注意することは、

month
1 月を意味する 0 から 12 月を意味する 11 までの、月を表す整数値。

「Blogger のドメイン、表示する投稿の数、年月日」を指定すると「前の投稿」のリンクを生成する createURL 関数を定義する。

// num が一桁の数字のとき先頭に 0 を加えて二桁にする
function padzero(num){
	return ("" + num).length == 1 ? "0" + num : num
}
function format(date){
	return date.getFullYear() + "-" + 
		padzero(date.getMonth()+1) + "-" + 
		padzero(date.getDate()) +
		encodeURIComponent("T" + padzero(date.getHours()) + ":" + 
			date.getMinutes() + ":" + 
			padzero(date.getSeconds()) + "+") +
		"09:00"
}
function createURL(url, numOfPost, year, month, date){
	return url + "search?updated-max=" + 
		format(new Date(year, month-1, date)) +
		"&max-results=" + numOfPost
}

 

自分のブログで 2008/4/9 よりも前の投稿を 10 件表示する URL を作成するには、

createURL("http://jutememo.blogspot.com/", 10, 2008, 4, 9);

結果は、

http://jutememo.blogspot.com/search?updated-max=2008-04-09T00%3A0%3A00%2B09:00&max-results=10

2009年4月18日土曜日

時刻を扱う - 特定の日付に属さない時間

例えば、「いつも朝の 6:30 から 6:40 までラジオ体操をする」という事柄を表現したいとする。「いつも」とあるように、この表現は特定の日付と関連したものではない。過去のある期間においてそういう事実があったことを記録したいわけでもなく、未来の予定について述べているわけでもない。「日常」という言葉通り、典型的な「生活パターン」というような抽象的なレベルの事象をどのように表現して扱うかという問題。

 

Access の日付/時刻型

さて、Access でデータを管理しようと思うと、上記の「時刻」をどのデータ型で扱えばいいのだろうか?最初に思い付くが「日付/時刻型」。(cf.  Access で使用できるフィールドのデータ型 (MDB) - Access - Microsoft Office Online)

「日常生活」と命名したテーブルを以下のように定義し、

090417-001

データを入力したとする。

090417-002

 

これに対して、次のように「年月日」を表示させるクエリを実行すると、

SELECT 日常生活.id, 日常生活.内容, Format([開始時刻],"yyyy/mm/dd hh:nn") AS 式1, Format([終了時刻],"yyyy/mm/dd hh:nn") AS 式2
FROM 日常生活;

時刻の前に `1899/12/30’ が表示される。これでは表現したいデータを素直に表現しているとは言い難い。 (+_+)

090417-003

ちなみにこの日付となる理由は、「フィールドのデータ型の設定を修正または変更する - Access - Microsoft Office Online」によると、

Access では、1899 年 12 月 30 日が日付 0 として使用されます。

 

時間について

プログラマのためのSQL 第2版 (P64) によると、

時間に関する重要な問題の 1 つに、時間には 3 種あるというのがあります。固定された出来事「彼は、13:00 に到着した」、期間「その旅は 3 時間かかる」、時間間隔「その列車は 10:00 に出発して 13:00 に到着する」は、それぞれ依存関係を持っています。 SQL-92 は、 INTERVAL データ型を導入していますが、ほとんどの現実の実装 (…) では、明白に持っていません。

(太文字は引用者による)

SQL – Wikipedia を見ると、SQL-92 で INTERVAL が追加されているのがわかる。

データ型の拡張 (可変長文字列、ビット、文字集合、日付・時刻・時間間隔 (DATE, TIME, TIMESTAMP, INTERVAL))

どうやらこの「時間間隔」というのが考える手がかりになりそうだ。

ちなみに Access と SQL のデータ型を比較した表を見ると、Access では INTERVAL 型を直接表現した型がないことがわかる。

 

ところで、Access ではユーザ定義型を作成することができない。(型とその型に適用できる演算子の定義がまともにできる RDB ってどれくらいあるのだろう?) よって、上記の要求を満たすドメインの値を素直に保持することはできない。そのため、結果として機能し得る型で代用することになる。

 

MySQL の Time 型

MySQL :: MySQL 5.1 Reference Manual :: 10.3.2 The TIME Type によると、

MySQL retrieves and displays TIME values in 'HH:MM:SS' format (or 'HHH:MM:SS' format for large hours values). TIME values may range from '-838:59:59' to '838:59:59'. The hours part may be so large because the TIME type can be used not only to represent a time of day (which must be less than 24 hours), but also elapsed time or a time interval between two events (which may be much greater than 24 hours, or even negative).

MySQL 5.1 では「時間間隔」と「一日の時刻」を同じ Time 型で表わすようだ。というより、「一日の時刻」を「時間間隔」で代用しているということかな。

 

Postgres の interval 型と time 型

Postgres は、「時間間隔」 (Interval) と「その日の時刻」(time) が分かれている。

 

Python の time オブジェクト

ところで、以前に Python で指定した日数後の日付を得るのに timedelta オブジェクト を使ったことがある。timedelta 周りを見ると time オブジェクト があるのに気がついた。(@_@)

time クラスは、

理想化された時刻表現で、あらゆる特定の日における影響から独立しており、毎日厳密に 24*60*60 秒であると仮定します ("うるう秒: leap seconds" の概念はありません)。 属性: hourminutesecondmicrosecond、 および tzinfo

(5.1.1 利用可能なデータ型 より)

まさにこれ。ただし、

time オブジェクト間の四則演算はサポートされていないので注意してください。

(time オブジェクト より)

「年月日」がなく「時・分・秒」だけので、上記の例を表現するには概念的にちょうどいい。

 

Visual Basic の日付

VB にも、似たような見かけの TimeSerial 関数 があったが、

    Debug.Print TimeSerial(6, 30, 0)
    Debug.Print Format(TimeSerial(6, 30, 0), "yyyy/mm/dd hh:nn")

実行すると、

6:30:00 
1899/12/30 06:30

あ~、内部では日付型かぁ…

@IT:連載:プロフェッショナルVB.NETプログラミング 第5回 日付時刻の取得とフォーマット によると、

日付と時刻の扱いは、Microsoft系BASICの歴史に限ってもすでに激変が起きている。初期のBASICでは、日付と時刻はそれぞれ文字列として扱われており、日付と時刻は別個の情報として扱われていた。(…)

Timeの場合日付は1899年12月30日となっているが、これはVB 6の日付を扱う起点となる日付である。(…)

VB.NETでは日付時刻の起点は0001/01/01 12:00:00である

うーむ… (@_@;)

 

Haskell の TimeOfDay 型

では、Haskell ではどうかな?と思い調べてみると、Time of day に、

data TimeOfDay

Time of day as represented in hour, minute and second (with picoseconds), typically used to express local time of day.

「時・分・秒」のみを値に持つ型がある。

先ほどの Python の Time オブジェクトと同様に、TimeOfDay 型は Num クラスのインスタンスではないので四則演算はできない。ただし、DiffTime 型という「時間間隔」を表わす型を利用すると計算を行うことができる。

最初に timeOfDayToTime 関数で TimeOfDay 型を DiffTime 型に変換。この関数は午前 0 時からの時間間隔を返してくれる。

timeOfDayToTime :: TimeOfDay -> DiffTime

090417-001

DiffTime 型は Num クラスのインスタンスなので、この型の値を足したり引いたりできる。それを上記の関数とは逆の timeToTimeOfDay で元の型に戻す。例えば、

import Data.Time
main = do
  let s = TimeOfDay 6 30 0
  print s
  let ds = timeOfDayToTime s
  print ds
  print $ timeToTimeOfDay $ ds + (secondsToDiffTime (10*60))

結果は、

06:30:00
23400s
06:40:00

 

対応する型がない場合の妥協

さて、話を元に戻して Access で時刻を扱うにはどうしよう。

一つは、年月日の情報は無視して、つまり ‘1899/12/30’ はないものとして時刻だけを「日付/時刻型」で扱う。とりあえず楽な方法。

自前でどうにかしたいなら、「時・分・秒」をそれぞれ別のフィールドで数値として扱い、それを一塊のものとして自分で思い込み、「時・分・秒」間での計算が必要なら関数を定義。ちょっと面倒だし、それに見合ういいことがあるのかわからない。

また別の方法として、NULL撲滅委員会 にあるように、

日付の列は文字型で宣言しておくべきです。(…) ほとんどの DBMS が日付型を用意していますが、私は個人的に使うメリットを感じません。暦日計算の場合など、必要なときだけキャストしています。

時刻を文字列として保持し、必要なときだけキャストする。ただし、年月日の情報は無視して日付型として計算を行う。この場合、最低でも文字列として時刻を保存するとき、時刻へとキャスト可能な形式であるか確認する必要となる。

2008年9月4日木曜日

Python で指定した日数後の日付を得る

例えば、今日 (2008.9.4) から 3 日後の日付を得たい場合、

from datetime import date, timedelta
print date.today() + timedelta(days=3)

結果、「2008-09-07」と表示される。

当然ながら、大晦日の 3 日後であるならば、

print date(2008,12,31) + timedelta(days=3)

「2009-01-03」と表示される。

つまり、日付による加算をしたい場合は、year, month, day の数値を得て計算するのではなく、 timedelta を使用すること。

 

datetimeモジュール

date オブジェクトdatetime モジュールで定義されており、

date オブジェクトは日付 (年、月、および日) を表します。(…)

today()

現在のローカルな日付を返します。

timedelta オブジェクト は、

timedelta オブジェクトは経過時間、すなわち二つの日付や時刻間の差を表します。