<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Groove Labo &#187; Python</title>
	<atom:link href="http://labo.opengroove.com/blog/category/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://labo.opengroove.com/blog</link>
	<description>株式会社オープングルーヴの開発者のブログ</description>
	<lastBuildDate>Wed, 25 Aug 2010 06:55:36 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>pytz &#8211; Pythonでタイムゾーンを扱うライブラリ</title>
		<link>http://labo.opengroove.com/blog/2009/08/05/pytz-python-timezone-library/</link>
		<comments>http://labo.opengroove.com/blog/2009/08/05/pytz-python-timezone-library/#comments</comments>
		<pubDate>Wed, 05 Aug 2009 14:58:18 +0000</pubDate>
		<dc:creator>omae</dc:creator>
				<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://labo.opengroove.com/blog/?p=321</guid>
		<description><![CDATA[omae です。

今回は Python でタイムゾーンが扱いたくなり Trac 0.11 より利用されている pytz を使ってみました。

pytz はタイムゾーンのデータベースを中に取り込んでおり、プラットホームに依存せずにタイムゾーンを扱えるようになっています。同種のライブラリとして Ruby では TZInfo などがあるようです。

大抵の Linux ディストリビューションでは /usr/share/zoneinfo にタイムゾーンのデータベース(tzdata)がインストールされているので二重にデータベースを持っているのが個人的には少し気持ち悪い感じがします。(連携できないのかな?)

http://pypi.python.org/pypi/pytz には egg ファイルが用意されているので、すぐにインストールできるようになっています。ということでさくっとインストールしてみてください。今回使用したのは pytz-2009j です。それでは使ってみます。

まずは、日本のタイムゾーンを取得します。これには pytz.timezone を用います。

&#62;&#62;&#62; from datetime import datetime, tzinfo
&#62;&#62;&#62; import pytz
&#62;&#62;&#62; tz_tokyo = pytz.timezone('Asia/Tokyo')
&#62;&#62;&#62; tz_tokyo
&#60;DstTzInfo 'Asia/Tokyo' CJT+9:00:00 STD&#62;
&#62;&#62;&#62; isinstance(tz_tokyo, tzinfo)
True


ここで返ってくるインスタンスは datetime.tzinfo のインスタンスになります。
次に UTC の現時刻を取得しますが、datetime.utcnow() は使わずに datetime.now(), pytz.utc を使ってタイムゾーンが指定された datetime インスタンスを取得しておきます。

&#62;&#62;&#62; pytz.utc
&#60;UTC&#62;
&#62;&#62;&#62; isinstance(pytz.utc, tzinfo)
True
&#62;&#62;&#62; utcnow [...]]]></description>
			<content:encoded><![CDATA[<p>omae です。</p>

<p>今回は Python でタイムゾーンが扱いたくなり Trac 0.11 より利用されている <a href="http://pypi.python.org/pypi/pytz">pytz</a> を使ってみました。</p>

<p>pytz はタイムゾーンのデータベースを中に取り込んでおり、プラットホームに依存せずにタイムゾーンを扱えるようになっています。同種のライブラリとして Ruby では <a href="http://tzinfo.rubyforge.org/">TZInfo</a> などがあるようです。</p>

<p>大抵の Linux ディストリビューションでは /usr/share/zoneinfo にタイムゾーンのデータベース(<a href="http://packages.debian.org/stable/tzdata">tzdata</a>)がインストールされているので二重にデータベースを持っているのが個人的には少し気持ち悪い感じがします。(連携できないのかな?)</p>

<p>http://pypi.python.org/pypi/pytz には egg ファイルが用意されているので、すぐにインストールできるようになっています。ということでさくっとインストールしてみてください。今回使用したのは <a href="http://pypi.python.org/packages/source/p/pytz/pytz-2009j.tar.gz">pytz-2009j</a> です。それでは使ってみます。</p>

<p>まずは、日本のタイムゾーンを取得します。これには pytz.timezone を用います。</p>

<pre><code>&gt;&gt;&gt; from datetime import datetime, tzinfo
&gt;&gt;&gt; import pytz
&gt;&gt;&gt; tz_tokyo = pytz.timezone('Asia/Tokyo')
&gt;&gt;&gt; tz_tokyo
&lt;DstTzInfo 'Asia/Tokyo' CJT+9:00:00 STD&gt;
&gt;&gt;&gt; isinstance(tz_tokyo, tzinfo)
True
</code></pre>

<p>ここで返ってくるインスタンスは datetime.tzinfo のインスタンスになります。<br />
次に UTC の現時刻を取得しますが、datetime.utcnow() は使わずに datetime.now(), pytz.utc を使ってタイムゾーンが指定された datetime インスタンスを取得しておきます。</p>

<pre><code>&gt;&gt;&gt; pytz.utc
&lt;UTC&gt;
&gt;&gt;&gt; isinstance(pytz.utc, tzinfo)
True
&gt;&gt;&gt; utcnow = datetime.now(pytz.utc)
&gt;&gt;&gt; utcnow
datetime.datetime(2009, 8, 5, 14, 10, 10, 744246, tzinfo=&lt;UTC&gt;)
&gt;&gt;&gt; format = '%Y-%m-%d %H:%M:%S %Z%z'
&gt;&gt;&gt; utcnow.strftime(format)
'2009-08-05 14:11:26 UTC+0000'
</code></pre>

<p>datetime.utcnow() を使用しない理由ですが、tzinfo クラスのメソッドのいくつかは datetime インスタンスにタイムゾーンが指定されていないと動作しないものがあるためです。たとえば pytz.utc.fromutc() に datetime.utcnow() を渡すとエラーになってしまいます。</p>

<pre><code>&gt;&gt;&gt; pytz.utc.fromutc(datetime.utcnow())
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in ?
ValueError: fromutc: dt.tzinfo is not self
&gt;&gt;&gt; pytz.utc.fromutc(utcnow)
datetime.datetime(2009, 8, 5, 14, 11, 26, 183394, tzinfo=&lt;UTC&gt;)
</code></pre>

<p>さて、tz_tokyo と utcnow を使って日本時間を表示してみます。</p>

<pre><code>&gt;&gt;&gt; tz_tokyo.fromutc(utcnow)
datetime.datetime(2009, 8, 5, 23, 11, 26, 183394, tzinfo=&lt;DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD&gt;)
&gt;&gt;&gt; tz_tokyo.fromutc(utcnow).strftime(format)
'2009-08-05 23:11:26 JST+0900'
</code></pre>

<p>ちゃんと +9 時間になっています。ついでにスウェーデンの現地時刻も表示してみます。</p>

<pre><code>&gt;&gt;&gt; tz_sweden = pytz.timezone('Europe/Stockholm')
&gt;&gt;&gt; tz_sweden
&lt;DstTzInfo 'Europe/Stockholm' CET+1:00:00 STD&gt;
&gt;&gt;&gt; tz_sweden.fromutc(utcnow).strftime(format)
'2009-08-05 15:37:07 CEST+0200'
</code></pre>

<p>日本時間から見て -7 時間のようです。</p>

<p>次は pytz からタイムゾーンの一覧ですが、これには pytz.common_timezones を用います。pytz.all_timezones というのもありますが、こちらにはすでに廃止されたタイムゾーンなども含まれているので通常使う分には common_timezones で問題ないと思います。</p>

<pre><code>&gt;&gt;&gt; len(pytz.common_timezones)
393
&gt;&gt;&gt; pytz.common_timezones[:10]
['Africa/Abidjan', 'Africa/Accra', 'Africa/Addis_Ababa', 'Africa/Algiers', 'Africa/Asmara', 'Africa/Bamako', 'Africa/Bangui', 'Africa/Banjul', 'Africa/Bissau', 'Africa/Blantyre']
&gt;&gt;&gt; pytz.common_timezones[-10:]
['Pacific/Wake', 'Pacific/Wallis', 'US/Alaska', 'US/Arizona', 'US/Central', 'US/Eastern', 'US/Hawaii', 'US/Mountain', 'US/Pacific', 'UTC']
</code></pre>

<p>このようにタイムゾーン名のリストになっています。実際には利用者に 300 を超えるタイムゾーンの中から選択してもらうのは大変ですので、タイムゾーンごとに GMT からのオフセットを取得することを考えてみます。</p>

<p><a href="http://www.python.org/doc/2.3/lib/datetime-tzinfo.html">tzinfo</a> のリファレンスを参照してみると utcoffset() というメソッドがありオフセットを取得するよいように見えるのですが、pytz が返してくる tzinfo インスタンスに対して utcoffset() を使用すると間違った値を返してくるタイムゾーンが出てきます。</p>

<pre><code>&gt;&gt;&gt; tz_tokyo.utcoffset(utcnow)
datetime.timedelta(0, 32400)    # GMT+09:00
&gt;&gt;&gt; tz_sweden.utcoffset(utcnow)
datetime.timedelta(0, 3600)     # GMT+02:00
&gt;&gt;&gt; tz_fiji = pytz.timezone('Pacific/Fiji')
&gt;&gt;&gt; tz_fiji.utcoffset(utcnow)
datetime.timedelta(0, 42840)    # GMT+11:54?
</code></pre>

<p>フィジーのタイムゾーンは <a href="http://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%82%B8%E3%83%BC">http://ja.wikipedia.org/wiki/フィジー</a> にある通り GMT+12:00 (43200) ですが GMT+11:54 (42840) という中途半端な値を返してきてしまいます。</p>

<p>この症状に似たのはないかとバグデータベースのほうを探してみると当てはまるものがあり workaround も示されていました。<a href="https://bugs.launchpad.net/pytz/+bug/310606">Bug #310606 in pytz: “Incorrect utcoffset returned from timezones”</a> です。これに従いやり直してみると</p>

<pre><code>&gt;&gt;&gt; tmp = datetime.now()
&gt;&gt;&gt; pytz.utc.localize(tmp) - tz_fiji.localize(tmp)
datetime.timedelta(0, 43200)    # GMT+12:00
</code></pre>

<p>となります。この式を用いて <code>(GMT+12:00) Pacific/Fiji</code> のような文字列に変換しオフセットでソートすれば少しは選択しやすくなると思います。</p>

<p>さらに選択しやすくするには</p>

<ul>
<li>国(ISO-3166)を選択してもらい pytz.country_timezones から該当するタイムゾーンだけを表示する (Google Calendar ではこのようになっています)</li>
<li>javascript を用いて <code>new Date().getTimezoneOffset()</code> に該当するタイムゾーンだけを表示する</li>
</ul>

<p>などの方法があるかと思います。</p>

<p>日本にいると夏時間がなく使用するタイムゾーンは1つしかないので、タイムゾーンを意識してコードを書くことはほとんどありませんが、pytz を知っておけば今後どこかで役に立つことがあるかも知れません。</p>
]]></content:encoded>
			<wfw:commentRss>http://labo.opengroove.com/blog/2009/08/05/pytz-python-timezone-library/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python unittest を使ってみる</title>
		<link>http://labo.opengroove.com/blog/2009/07/30/python-unittest-%e3%82%92%e4%bd%bf%e3%81%a3%e3%81%a6%e3%81%bf%e3%82%8b/</link>
		<comments>http://labo.opengroove.com/blog/2009/07/30/python-unittest-%e3%82%92%e4%bd%bf%e3%81%a3%e3%81%a6%e3%81%bf%e3%82%8b/#comments</comments>
		<pubDate>Thu, 30 Jul 2009 04:02:00 +0000</pubDate>
		<dc:creator>sugimoto</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[テスト]]></category>

		<guid isPermaLink="false">http://labo.opengroove.com/blog/?p=256</guid>
		<description><![CDATA[sugimoto です。

Pythonの単体テストのツール unittest を使ってみました。

1. まずはマニュアル通りに。。


Python &#8211; unittestのマニュアルから、TestSequenceFunctions を実行します。



# python testsequecefunctions.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.002s

OK



普通に成功しましたね。


2. TestSuite を実行する


今度は複数のTestCaseからなる、TestSuiteを実行してみます。



TestCaseは同じものを使ったので、命名のセンスが悪くてすいません。。


2つのTestCaseをまとめて実行するTestSuite

[testsuite.py]


import unittest
import testsequecefunctions as TestSequenceFunctions
import testsequecefunctions2 as TestSequenceFunctions2

suite1 = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions.TestSequenceFunctions)
suite2 = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions2.TestSequenceFunctions2)
suite = unittest.TestSuite([suite1, suite2])
print suite.countTestCases()

runner = unittest.TextTestRunner()
runner.run(suite)


実行すると


# python testsuite.py
6
......
----------------------------------------------------------------------
Ran 6 tests in 0.002s

OK


6個のテストがすべてパスしました。

3. trac plugin をテストしてみる


trac のestimationtools pluginをテストしてみます。すでにテストコードも提供されているので、今回は実行するだけです。



# unzip estimationtoolsplugin-r6309.zip
# cd estimationtoolsplugin/trunk/estimationtools/tests
# ll
total 24
-rw-r--r-- 1 root root 9264 Jul [...]]]></description>
			<content:encoded><![CDATA[<p>sugimoto です。</p>

<p>Pythonの単体テストのツール unittest を使ってみました。</p>

<h3>1. まずはマニュアル通りに。。</h3>

<p>
<a href="http://docs.python.org/library/unittest.html">Python &#8211; unittest</a>のマニュアルから、TestSequenceFunctions を実行します。
</p>

<pre>
# python testsequecefunctions.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.002s

OK
</pre>

<p>
普通に成功しましたね。
</p>

<h3>2. TestSuite を実行する</h3>

<p>
今度は複数のTestCaseからなる、TestSuiteを実行してみます。
</p>

<p>
TestCaseは同じものを使ったので、命名のセンスが悪くてすいません。。
</p>

<h4>2つのTestCaseをまとめて実行するTestSuite</h4>

<p><b>[testsuite.py]</b></p>

<pre>
import unittest
import testsequecefunctions as TestSequenceFunctions
import testsequecefunctions2 as TestSequenceFunctions2

suite1 = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions.TestSequenceFunctions)
suite2 = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions2.TestSequenceFunctions2)
suite = unittest.TestSuite([suite1, suite2])
print suite.countTestCases()

runner = unittest.TextTestRunner()
runner.run(suite)
</pre>

<p>実行すると</p>

<pre>
# python testsuite.py
6
......
----------------------------------------------------------------------
Ran 6 tests in 0.002s

OK
</pre>

<p>6個のテストがすべてパスしました。</p>

<h3>3. trac plugin をテストしてみる</h3>

<p>
trac の<a href="http://trac-hacks.org/wiki/EstimationToolsPlugin">estimationtools plugin</a>をテストしてみます。すでにテストコードも提供されているので、今回は実行するだけです。
</p>

<pre>
# unzip estimationtoolsplugin-r6309.zip
# cd estimationtoolsplugin/trunk/estimationtools/tests
# ll
total 24
-rw-r--r-- 1 root root 9264 Jul 29 11:18 burndownchart.py
-rw-r--r-- 1 root root 2696 Jul 30 10:46 hoursremaining.py
-rw-r--r-- 1 root root 2283 Jan 26  2009 workloadchart.py
</pre>

<p>
そのまま実行できるようにスクリプトの最後に以下のコードを追加しておきます。
</p>

<pre>
if __name__ == "__main__":
    unittest.main()
</pre>

<p>
そして実行
</p>

<pre>
# python burndownchart.py
Traceback (most recent call last):
  File "burndownchart.py", line 3, in ?
    from estimationtools.burndownchart import BurndownChart
ImportError: No module named estimationtools.burndownchart
</pre>

<p>
エラーになりました。。
</p>

<p>
estimationtools.burndownchart がないということですね。。
</p>

<p>
plugin 本体のディレクトリにパスを通しておきます。
</p>

<pre>
# export PYTHONPATH=/root/plugins/estimationtoolsplugin/trunk/
</pre>

<p>
再度実行します。
</p>

<pre>
# python burndownchart.py
...FFF......
======================================================================
FAIL: test_calculate_timetable_with_closed_and_reopened_ticket (__main__.BurndownChartTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "burndownchart.py", line 140, in test_calculate_timetable_with_closed_and_reopened_ticket
    self.assertEqual(timetable, {day1: Decimal(10), day2: Decimal(0), day3: Decimal(0), day4: Decimal(5)})
AssertionError: {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("0"), datetime.date(2009, 8, 1): Decimal("0"), datetime.date(2009, 8, 2): Decimal("5")} != {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("10"), datetime.date(2009, 8, 1): Decimal("0"), datetime.date(2009, 8, 2): Decimal("5")}

======================================================================
FAIL: test_calculate_timetable_with_closed_ticket (__main__.BurndownChartTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "burndownchart.py", line 113, in test_calculate_timetable_with_closed_ticket
    self.assertEqual(timetable, {day1: Decimal(10), day2: Decimal(5), day3: Decimal(0)})
AssertionError: {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("0"), datetime.date(2009, 8, 1): Decimal("0")} != {datetime.date(2009, 7, 31): Decimal("5"), datetime.date(2009, 7, 30): Decimal("10"), datetime.date(2009, 8, 1): Decimal("0")}

======================================================================
FAIL: test_calculate_timetable_with_closed_ticket2 (__main__.BurndownChartTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "burndownchart.py", line 126, in test_calculate_timetable_with_closed_ticket2
    self.assertEqual(timetable, {day1: Decimal(10), day2: Decimal(0), day3: Decimal(0)})
AssertionError: {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("0"), datetime.date(2009, 8, 1): Decimal("0")} != {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("10"), datetime.date(2009, 8, 1): Decimal("0")}

----------------------------------------------------------------------
Ran 12 tests in 0.478s

FAILED (failures=3)
#
</pre>

<p>
今度はうまくいった。。と思ったら、なぜかテストが失敗しましたね。。
</p>

<h3>4. estimationtools plugin のtest suite を実行する</h3>

<p>
estimationtools plugin には3つのテストがあるので、すべて実行するためのスクリプトを作ります。
</p>

<p><b>[testsuite.py]</b></p>

<pre>
import unittest
import burndownchart as burndownchart
import hoursremaining as hoursremaining
import workloadchart as workloadchart

runner = unittest.TextTestRunner()
suite = unittest.TestLoader().loadTestsFromTestCase(burndownchart.BurndownChartTestCase)
runner.run(suite)

suite = unittest.TestLoader().loadTestsFromTestCase(hoursremaining.HoursRemainingTestCase)
runner.run(suite)

suite = unittest.TestLoader().loadTestsFromTestCase(workloadchart.WorkloadChartTestCase)
runner.run(suite)
</pre>

<p>3つのテストをロードして、実行するだけです。簡単です。</p>

<p>実行してみます。</p>

<pre>
# python testsuite.py
...FFF......
======================================================================
FAIL: test_calculate_timetable_with_closed_and_reopened_ticket (burndownchart.BurndownChartTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/root/plugins/estimationtoolsplugin/trunk/estimationtools/tests/burndownchart.py", line 140, in test_calculate_timetable_with_closed_and_reopened_ticket
    self.assertEqual(timetable, {day1: Decimal(10), day2: Decimal(0), day3: Decimal(0), day4: Decimal(5)})
AssertionError: {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("0"), datetime.date(2009, 8, 1): Decimal("0"), datetime.date(2009, 8, 2): Decimal("5")} != {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("10"), datetime.date(2009, 8, 1): Decimal("0"), datetime.date(2009, 8, 2): Decimal("5")}

======================================================================
FAIL: test_calculate_timetable_with_closed_ticket (burndownchart.BurndownChartTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/root/plugins/estimationtoolsplugin/trunk/estimationtools/tests/burndownchart.py", line 113, in test_calculate_timetable_with_closed_ticket
    self.assertEqual(timetable, {day1: Decimal(10), day2: Decimal(5), day3: Decimal(0)})
AssertionError: {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("0"), datetime.date(2009, 8, 1): Decimal("0")} != {datetime.date(2009, 7, 31): Decimal("5"), datetime.date(2009, 7, 30): Decimal("10"), datetime.date(2009, 8, 1): Decimal("0")}

======================================================================
FAIL: test_calculate_timetable_with_closed_ticket2 (burndownchart.BurndownChartTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/root/plugins/estimationtoolsplugin/trunk/estimationtools/tests/burndownchart.py", line 126, in test_calculate_timetable_with_closed_ticket2
    self.assertEqual(timetable, {day1: Decimal(10), day2: Decimal(0), day3: Decimal(0)})
AssertionError: {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("0"), datetime.date(2009, 8, 1): Decimal("0")} != {datetime.date(2009, 7, 31): Decimal("0"), datetime.date(2009, 7, 30): Decimal("10"), datetime.date(2009, 8, 1): Decimal("0")}

----------------------------------------------------------------------
Ran 12 tests in 0.619s

FAILED (failures=3)
.....
----------------------------------------------------------------------
Ran 5 tests in 0.692s

OK
..
----------------------------------------------------------------------
Ran 2 tests in 0.126s

OK
</pre>

<p>
1つめのテストケースはやっぱり失敗しますが、残りのテストケースはすべて成功しました。
</p>

<p>
今回は既存のplugin に添付されているテストケースを使いましたが、自分がpluginを作ったときもテストケースを書きたいと思います。
</p>

<h5>参考</h5>

<ul>
    <li><a href="http://docs.python.org/library/unittest.html">Python &#8211; unittest</a></li>
    <li><a href="http://trac-hacks.org/wiki/EstimationToolsPlugin">estimationtools plugin</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://labo.opengroove.com/blog/2009/07/30/python-unittest-%e3%82%92%e4%bd%bf%e3%81%a3%e3%81%a6%e3%81%bf%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>関数のテストをしてみる</title>
		<link>http://labo.opengroove.com/blog/2009/07/23/%e9%96%a2%e6%95%b0%e3%81%ae%e3%83%86%e3%82%b9%e3%83%88%e3%82%92%e3%81%97%e3%81%a6%e3%81%bf%e3%82%8b/</link>
		<comments>http://labo.opengroove.com/blog/2009/07/23/%e9%96%a2%e6%95%b0%e3%81%ae%e3%83%86%e3%82%b9%e3%83%88%e3%82%92%e3%81%97%e3%81%a6%e3%81%bf%e3%82%8b/#comments</comments>
		<pubDate>Thu, 23 Jul 2009 11:18:05 +0000</pubDate>
		<dc:creator>morimoto</dc:creator>
				<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://labo.opengroove.com/blog/?p=213</guid>
		<description><![CDATA[こんばんわ。morimotoです。

前回の数値判定の関数を一括してテストするためにテストクラスを書いてみました。
少々汚いですが暴動とかデモとか起こさないでください。。。

まずはテストクラス function_test.py


# -*- coding: utf-8 -*-
class FunctionTest:
    def display_all(self, tests={}):
        for namespace in tests:
            print ""
            print "*" * 15 + (namespace + [...]]]></description>
			<content:encoded><![CDATA[<p>こんばんわ。morimotoです。</p>

<p>前回の数値判定の関数を一括してテストするためにテストクラスを書いてみました。
少々汚いですが暴動とかデモとか起こさないでください。。。</p>

<p>まずはテストクラス function_test.py</p>

<pre>
# -*- coding: utf-8 -*-
class FunctionTest:
    def display_all(self, tests={}):
        for namespace in tests:
            print ""
            print "*" * 15 + (namespace + " Tests").center(30) + "*" * 15
            print ""
            cases = tests.get(namespace, [])
            for case in cases:
                functions = case.get('functions', [])
                args_list = case.get('args_list', [])
                args_default = case.get('args_default', {})
                self.display(namespace, functions, args_list, args_default)

    def display(self, namespace, functions, args_list, args_default={}):
        if functions:
            format, sep = self.get_format(functions[:], args_list[:])
            if args_default:
                print " * set args default values : %s" % ",".join([" %s = %s"%(name, args_default[name],) for name in args_default])
            print sep
            print format % (('args',) + tuple(functions[:]))
            print sep
            for args in args_list:
                print format % ((str(args),) + tuple([self.execute(namespace, func, args, args_default) for func in functions[:]]))
            print sep
            print ''

    def get_format(self, functions, args_list):
        ph = lambda v: '%' + '%s'%v + 's'
        args_len = args_list and max([len(str(args)) for args in args_list[:]]) or 0
        func_lens = [len(str(func)) for func in functions[:]]
        format = '| ' + ph(args_len) + ' || ' + ' | '.join([ph(fl) for fl in func_lens[:]]) + ' |'
        sep = '+' + '-' * (args_len + 2) + '++' + '+'.join(['-' * (fl+2) for fl in func_lens[:]]) + '+'
        return format, sep

    def execute(self, namespace, function_name, args, args_default={}):
        my_module = __import__(namespace)
        my_func = getattr(my_module, function_name)
        return apply(my_func, self.args_to_tuple(args), self.args_to_dict(args, args_default))

    def args_to_tuple(self, args):
        if isinstance(args, tuple):
            return args
        if isinstance(args, list):
            return tuple(args)
        if isinstance(args, str):
            return tuple([args,])
        return tuple([])
    
    def args_to_dict(self, args, args_default={}):
        if isinstance(args, dict):
            args.update(args_default)
            return args
        return args_default

</pre>

<p>前回のutilities.py (try-catch でパースするのもテストしてみる)</p>

<pre>
# -*- coding: utf-8 -*-
import re

# Convert functions
def parseInt(value, default=None):
    (ret,) = validates_integer_of(value) and (int(value),) or \
            (validates_number_of(value) and (int(float(value)),) or (default,))
    return ret

def _parseInt(value, default=None):
    try:
        return int(value)
    except:
        return default

# Validate functions
def validates_number_of(value):
    return re.match(r'^(?![-+]0+$)[-+]?([1-9][0-9]*)?[0-9](\.[0-9]+)?$', '%s'%value) and True or False

def validates_integer_of(value):
    return re.match(r'^(?![-+]0*$)[-+]?([1-9][0-9]*)?0?$', '%s'%value) and True or False

def validates_float_of(value):
    return validates_number_of(value) and not validates_integer_of(value) or False

</pre>

<p>最後にテストするための test.py</p>

<pre>
# -*- coding: utf-8 -*-
from function_test import FunctionTest
from utilities import *

test_values = [
    "123456",
    "0",
    "-9",
    "+5",
    "+9",
    "0.0000",
    "1234.56",
    "-123.45",
    "+123.45",
    "-0.123",
    "123.00000",
    "+00000000",
    "-00000000",
    "+0",
    "-0",
    "ABCDEF",
    "1+23",
    "123-",
    "-.123",
    "123.",
    "00012",
    ".123",
    "+0000",
    "-0000",
    "+0000.22",
    "+",
    "-",
    ["12345"],
    ("12345",),
    {"value": "12345"},
]

test_functions = {
    'utilities': [
        {
            'functions': ['validates_number_of', 'validates_integer_of', 'validates_float_of', ],
            'args_list': test_values,
        },
        {
            'functions': ['parseInt', '_parseInt', ],
            'args_list': test_values,
            'args_default': { 'default': None, },
        },
   ]
}

ft = FunctionTest()
ft.display_all(test_functions)

</pre>

<p><li>test_functions の &#8216;utilities&#8217; の部分は最初にimportしているテストしたい名前空間名。</li>
<li>配列中の dictionary は引数が同じ（出来れば引数の数や名前が同じ）場合はまとめてしまって構わないです。</li>
<li>&#8216;functions&#8217; は名前の通り関数名のリスト</li>
<li>&#8216;args_list&#8217; はテストしたい引数のリスト。</li>
<li>&#8216;args_default&#8217; は任意で値をセットしたい場合に引数名をキーに対して値を入れる。</li>
<li>test_values の下３つはテストクラスのテスト用（笑）</li></p>

<p>この3つのファイルを同じ階層に置いていただき、後はコンソールから</p>

<pre>
python test.py
</pre>

<p>を実行するだけです。</p>

<p>結果</p>

<pre>
>python test.py

***************       utilities Tests        ***************

+--------------------++---------------------+----------------------+--------------------+
|               args || validates_number_of | validates_integer_of | validates_float_of |
+--------------------++---------------------+----------------------+--------------------+
|             123456 ||                True |                 True |              False |
|                  0 ||                True |                 True |              False |
|                 -9 ||                True |                 True |              False |
|                 +5 ||                True |                 True |              False |
|                 +9 ||                True |                 True |              False |
|             0.0000 ||                True |                False |               True |
|            1234.56 ||                True |                False |               True |
|            -123.45 ||                True |                False |               True |
|            +123.45 ||                True |                False |               True |
|             -0.123 ||                True |                False |               True |
|          123.00000 ||                True |                False |               True |
|          +00000000 ||               False |                False |              False |
|          -00000000 ||               False |                False |              False |
|                 +0 ||               False |                False |              False |
|                 -0 ||               False |                False |              False |
|             ABCDEF ||               False |                False |              False |
|               1+23 ||               False |                False |              False |
|               123- ||               False |                False |              False |
|              -.123 ||               False |                False |              False |
|               123. ||               False |                False |              False |
|              00012 ||               False |                False |              False |
|               .123 ||               False |                False |              False |
|              +0000 ||               False |                False |              False |
|              -0000 ||               False |                False |              False |
|           +0000.22 ||               False |                False |              False |
|                  + ||               False |                False |              False |
|                  - ||               False |                False |              False |
|          ['12345'] ||                True |                 True |              False |
|         ('12345',) ||                True |                 True |              False |
| {'value': '12345'} ||                True |                 True |              False |
+--------------------++---------------------+----------------------+--------------------+

 * set args default values :  default = None
+--------------------++----------+-----------+
|               args || parseInt | _parseInt |
+--------------------++----------+-----------+
|             123456 ||   123456 |    123456 |
|                  0 ||        0 |         0 |
|                 -9 ||       -9 |        -9 |
|                 +5 ||        5 |         5 |
|                 +9 ||        9 |         9 |
|             0.0000 ||        0 |      None |
|            1234.56 ||     1234 |      None |
|            -123.45 ||     -123 |      None |
|            +123.45 ||      123 |      None |
|             -0.123 ||        0 |      None |
|          123.00000 ||      123 |      None |
|          +00000000 ||     None |         0 |
|          -00000000 ||     None |         0 |
|                 +0 ||     None |         0 |
|                 -0 ||     None |         0 |
|             ABCDEF ||     None |      None |
|               1+23 ||     None |      None |
|               123- ||     None |      None |
|              -.123 ||     None |      None |
|               123. ||     None |      None |
|              00012 ||     None |        12 |
|               .123 ||     None |      None |
|              +0000 ||     None |         0 |
|              -0000 ||     None |         0 |
|           +0000.22 ||     None |      None |
|                  + ||     None |      None |
|                  - ||     None |      None |
|          ['12345'] ||    12345 |     12345 |
|         ('12345',) ||    12345 |     12345 |
| {'value': '12345'} ||    12345 |     12345 |
+--------------------++----------+-----------+
</pre>

<p>_parseInt のほうはボロボロでした。
int()よ、しっかりしてください・・・。</p>

<p>以上morimotoでした。</p>
]]></content:encoded>
			<wfw:commentRss>http://labo.opengroove.com/blog/2009/07/23/%e9%96%a2%e6%95%b0%e3%81%ae%e3%83%86%e3%82%b9%e3%83%88%e3%82%92%e3%81%97%e3%81%a6%e3%81%bf%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mac上の複数バージョンのpythonを切り替える簡単な方法</title>
		<link>http://labo.opengroove.com/blog/2009/07/22/mac%e4%b8%8a%e3%81%ae%e8%a4%87%e6%95%b0%e3%83%90%e3%83%bc%e3%82%b8%e3%83%a7%e3%83%b3%e3%81%aepython%e3%82%92%e5%88%87%e3%82%8a%e6%9b%bf%e3%81%88%e3%82%8b%e7%b0%a1%e5%8d%98%e3%81%aa%e6%96%b9%e6%b3%95/</link>
		<comments>http://labo.opengroove.com/blog/2009/07/22/mac%e4%b8%8a%e3%81%ae%e8%a4%87%e6%95%b0%e3%83%90%e3%83%bc%e3%82%b8%e3%83%a7%e3%83%b3%e3%81%aepython%e3%82%92%e5%88%87%e3%82%8a%e6%9b%bf%e3%81%88%e3%82%8b%e7%b0%a1%e5%8d%98%e3%81%aa%e6%96%b9%e6%b3%95/#comments</comments>
		<pubDate>Wed, 22 Jul 2009 11:23:18 +0000</pubDate>
		<dc:creator>matsushita</dc:creator>
				<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://labo.opengroove.com/blog/?p=208</guid>
		<description><![CDATA[こんにちは。松下です。

ごくごく最近からですが、macを使って開発を行っています。

また、ごくごく最近からですが、pythonを使って開発を行っています。

macには標準で、python2.5.1が入っていましたが、3.0を使いたかったのでmac portsで3.0をインストールしました。

今度は2.4を仕事で使うことになったので、2.4をインストールしました。
用途によって、複数バージョンのpythonを使い分けていたのですが、結構面倒くさいです。

で、何かいい方法をないか探したところ、複数バージョンのpythonを切り替えることができるpython_selectというものを発見しました。

早速インストール。

$sudo port install python_select

以下のような方法で、バージョンを切り替えることができます。

$python_select python24
Selecting version "python24" for python

バージョンを確認すると、見事に切り替わってます。

$python -V
Python 2.4.6

バージョンの確認は以下のようにします。

$ python_select -l
Available versions:
none python24 python25 python25-apple python30

バージョンの切り替えが面倒だなと思っている方は是非お試しください。
]]></description>
			<content:encoded><![CDATA[<p>こんにちは。松下です。</p>

<p>ごくごく最近からですが、macを使って開発を行っています。</p>

<p>また、ごくごく最近からですが、pythonを使って開発を行っています。</p>

<p>macには標準で、python2.5.1が入っていましたが、3.0を使いたかったのでmac portsで3.0をインストールしました。</p>

<p>今度は2.4を仕事で使うことになったので、2.4をインストールしました。
用途によって、複数バージョンのpythonを使い分けていたのですが、結構面倒くさいです。</p>

<p>で、何かいい方法をないか探したところ、複数バージョンのpythonを切り替えることができるpython_selectというものを発見しました。</p>

<p>早速インストール。</p>

<pre>$sudo port install python_select</pre>

<p>以下のような方法で、バージョンを切り替えることができます。</p>

<pre>$python_select python24
Selecting version "python24" for python</pre>

<p>バージョンを確認すると、見事に切り替わってます。</p>

<pre>$python -V
Python 2.4.6</pre>

<p>バージョンの確認は以下のようにします。</p>

<pre>$ python_select -l
Available versions:
none python24 python25 python25-apple python30</pre>

<p>バージョンの切り替えが面倒だなと思っている方は是非お試しください。</p>
]]></content:encoded>
			<wfw:commentRss>http://labo.opengroove.com/blog/2009/07/22/mac%e4%b8%8a%e3%81%ae%e8%a4%87%e6%95%b0%e3%83%90%e3%83%bc%e3%82%b8%e3%83%a7%e3%83%b3%e3%81%aepython%e3%82%92%e5%88%87%e3%82%8a%e6%9b%bf%e3%81%88%e3%82%8b%e7%b0%a1%e5%8d%98%e3%81%aa%e6%96%b9%e6%b3%95/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>pythonで文字列が数値かどうかを判断する</title>
		<link>http://labo.opengroove.com/blog/2009/07/14/python%e3%81%a7%e6%96%87%e5%ad%97%e5%88%97%e3%81%8c%e6%95%b0%e5%80%a4%e3%81%8b%e3%81%a9%e3%81%86%e3%81%8b%e3%82%92%e5%88%a4%e6%96%ad%e3%81%99%e3%82%8b/</link>
		<comments>http://labo.opengroove.com/blog/2009/07/14/python%e3%81%a7%e6%96%87%e5%ad%97%e5%88%97%e3%81%8c%e6%95%b0%e5%80%a4%e3%81%8b%e3%81%a9%e3%81%86%e3%81%8b%e3%82%92%e5%88%a4%e6%96%ad%e3%81%99%e3%82%8b/#comments</comments>
		<pubDate>Tue, 14 Jul 2009 13:48:39 +0000</pubDate>
		<dc:creator>morimoto</dc:creator>
				<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://labo.opengroove.com/blog/?p=136</guid>
		<description><![CDATA[morimotoです。

今回は数値変換（int()）を行う前に、数値変換できる文字列なのかを検証してみましょうという記事です。

まず数値変換についてです。

&#62;&#62;&#62; s1 = "12345"
&#62;&#62;&#62; s2 = "abcde"
&#62;&#62;&#62; int(s1)
12345
&#62;&#62;&#62; int(s2)
Traceback (most recent call last):
  File "", line 1, in ?
ValueError: invalid literal for int(): abcde

ｓ１は数値の文字列なので変換可能ですが、s2は当然数値ではないので変換は出来ません。

エラーを吐かれたほうが親切な場合も多いですが、煩わしいと思う方も居るかもしれません。

そこで、変換前に入力値が数値かどうかを判断してから数値を変換するメソッドを作ってみました。

数値検証用メソッド

# Validate functions
# 数値の文字列ならTrueです（Long型 30L とかは対象外）
def validates_number_of(value):
    return re.match(r'^(?![-+]0+$)[-+]?([1-9][0-9]*)?[0-9](\.[0-9]+)?$', '%s'%value) and True or False

# 整数値かどうかの検証
def validates_integer_of(value):
    return re.match(r'^(?![-+]0*$)[-+]?([1-9][0-9]*)?0?$', '%s'%value) and True or False

# 数値でintegerじゃなかったらfloatよね？（ちょっと手抜き）
def validates_float_of(value):
 [...]]]></description>
			<content:encoded><![CDATA[<p>morimotoです。</p>

<p>今回は数値変換（int()）を行う前に、数値変換できる文字列なのかを検証してみましょうという記事です。</p>

<p>まず数値変換についてです。</p>

<pre>&gt;&gt;&gt; s1 = "12345"
&gt;&gt;&gt; s2 = "abcde"
&gt;&gt;&gt; int(s1)
12345
&gt;&gt;&gt; int(s2)
Traceback (most recent call last):
  File "", line 1, in ?
ValueError: invalid literal for int(): abcde</pre>

<p>ｓ１は数値の文字列なので変換可能ですが、s2は当然数値ではないので変換は出来ません。</p>

<p>エラーを吐かれたほうが親切な場合も多いですが、煩わしいと思う方も居るかもしれません。</p>

<p>そこで、変換前に入力値が数値かどうかを判断してから数値を変換するメソッドを作ってみました。</p>

<h3>数値検証用メソッド</h3>

<pre># Validate functions
# 数値の文字列ならTrueです（Long型 30L とかは対象外）
def validates_number_of(value):
    return re.match(r'^(?![-+]0+$)[-+]?([1-9][0-9]*)?[0-9](\.[0-9]+)?$', '%s'%value) and True or False

# 整数値かどうかの検証
def validates_integer_of(value):
    return re.match(r'^(?![-+]0*$)[-+]?([1-9][0-9]*)?0?$', '%s'%value) and True or False

# 数値でintegerじゃなかったらfloatよね？（ちょっと手抜き）
def validates_float_of(value):
    return validates_number_of(value) and not validates_integer_of(value) or False</pre>

<h4>テスト</h4>

<pre>+--------------------++---------------------+----------------------+--------------------+
|               args || validates_number_of | validates_integer_of | validates_float_of |
+--------------------++---------------------+----------------------+--------------------+
|             123456 ||                True |                 True |              False |
|                  0 ||                True |                 True |              False |
|                 -9 ||                True |                 True |              False |
|                 +5 ||                True |                 True |              False |
|                 +9 ||                True |                 True |              False |
|             0.0000 ||                True |                False |               True |
|            1234.56 ||                True |                False |               True |
|            -123.45 ||                True |                False |               True |
|            +123.45 ||                True |                False |               True |
|             -0.123 ||                True |                False |               True |
|          123.00000 ||                True |                False |               True |
|          +00000000 ||               False |                False |              False |
|          -00000000 ||               False |                False |              False |
|                 +0 ||               False |                False |              False |
|                 -0 ||               False |                False |              False |
|             ABCDEF ||               False |                False |              False |
|               1+23 ||               False |                False |              False |
|               123- ||               False |                False |              False |
|              -.123 ||               False |                False |              False |
|               123. ||               False |                False |              False |
|              00012 ||               False |                False |              False |
|               .123 ||               False |                False |              False |
|              +0000 ||               False |                False |              False |
|              -0000 ||               False |                False |              False |
|           +0000.22 ||               False |                False |              False |
|                  + ||               False |                False |              False |
|                  - ||               False |                False |              False |
+--------------------++---------------------+----------------------+--------------------+</pre>

<h3>数値変換メソッド</h3>

<p>上記検証用のメソッドを用いて作ります。</p>

<pre># 汚くて申し訳ない！
def to_int(value, default=None):
    (ret,) = validates_integer_of(value) and (int(value),) or \
            (validates_number_of(value) and (int(float(value)),) or (default,))
    return ret</pre>

<h4>テスト</h4>

<pre>+--------------------++--------+
|               args || to_int |
+--------------------++--------+
|             123456 || 123456 |
|                  0 ||      0 |
|                 -9 ||     -9 |
|                 +5 ||      5 |
|                 +9 ||      9 |
|             0.0000 ||      0 |
|            1234.56 ||   1234 |
|            -123.45 ||   -123 |
|            +123.45 ||    123 |
|             -0.123 ||      0 |
|          123.00000 ||    123 |
|          +00000000 ||   None |
|          -00000000 ||   None |
|                 +0 ||   None |
|                 -0 ||   None |
|             ABCDEF ||   None |
|               1+23 ||   None |
|               123- ||   None |
|              -.123 ||   None |
|               123. ||   None |
|              00012 ||   None |
|               .123 ||   None |
|              +0000 ||   None |
|              -0000 ||   None |
|           +0000.22 ||   None |
|                  + ||   None |
|                  - ||   None |
+--------------------++--------+</pre>

<p>入力値がintegerでなかったらNoneを返すメソッドができました。</p>

<pre>
s = "123o123"
i = to_int(s)
if i:
    print "数値ですよ"
else:
    print "数値じゃないよ"
</pre>

<p>みたいな使い方もできるのかな？</p>

<p>以上、morimotoでした。</p>
]]></content:encoded>
			<wfw:commentRss>http://labo.opengroove.com/blog/2009/07/14/python%e3%81%a7%e6%96%87%e5%ad%97%e5%88%97%e3%81%8c%e6%95%b0%e5%80%a4%e3%81%8b%e3%81%a9%e3%81%86%e3%81%8b%e3%82%92%e5%88%a4%e6%96%ad%e3%81%99%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pythonでの日付関連処理</title>
		<link>http://labo.opengroove.com/blog/2009/07/09/python%e3%81%a7%e3%81%ae%e6%97%a5%e4%bb%98%e9%96%a2%e9%80%a3%e5%87%a6%e7%90%86/</link>
		<comments>http://labo.opengroove.com/blog/2009/07/09/python%e3%81%a7%e3%81%ae%e6%97%a5%e4%bb%98%e9%96%a2%e9%80%a3%e5%87%a6%e7%90%86/#comments</comments>
		<pubDate>Thu, 09 Jul 2009 02:25:04 +0000</pubDate>
		<dc:creator>matsushita</dc:creator>
				<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://labo.opengroove.com/blog/?p=77</guid>
		<description><![CDATA[pythonの日付関連の操作メモです。

pythonは、標準でdatetimeモジュール、calendarモジュール、timeモジュールに日付関連の操作が提供されています。まずは、pythonの標準モジュールでの日付処理をまとめてみます。

１．標準モジュールを使った日付処理

現在の日付を得る

from datetime import date
date.today() # datetime.date(2009, 7, 8)

from datetime import date
import time
date.fromtimestamp(time.time()) # datetime.date(2009, 7, 8)

現在日時を得る

from datetime import datetime
datetime.now() # datetime.datetime(2009, 7, 8, 22, 59, 0, 688787)
datetime.today() # datetime.datetime(2009, 7, 8, 23, 2, 53, 892892)

from datetime import datetime
import time
datetime.fromtimestamp(time.time()) # datetime.datetime(2009, 7, 8, 23, 24, 39, 457040)

日付オブジェクトの年月日時分秒を取得する

from datetime import datetime
now = datetime.now() # datetime.datetime(2009, 7, [...]]]></description>
			<content:encoded><![CDATA[<p>pythonの日付関連の操作メモです。</p>

<p>pythonは、標準でdatetimeモジュール、calendarモジュール、timeモジュールに日付関連の操作が提供されています。まずは、pythonの標準モジュールでの日付処理をまとめてみます。</p>

<h2>１．標準モジュールを使った日付処理</h2>

<h3>現在の日付を得る</h3>

<pre>from datetime import date
date.today() # datetime.date(2009, 7, 8)</pre>

<pre>from datetime import date
import time
date.fromtimestamp(time.time()) # datetime.date(2009, 7, 8)</pre>

<h3>現在日時を得る</h3>

<pre>from datetime import datetime
datetime.now() # datetime.datetime(2009, 7, 8, 22, 59, 0, 688787)
datetime.today() # datetime.datetime(2009, 7, 8, 23, 2, 53, 892892)</pre>

<pre>from datetime import datetime
import time
datetime.fromtimestamp(time.time()) # datetime.datetime(2009, 7, 8, 23, 24, 39, 457040)</pre>

<h3>日付オブジェクトの年月日時分秒を取得する</h3>

<pre>from datetime import datetime
now = datetime.now() # datetime.datetime(2009, 7, 8, 22, 59, 0, 688787)
now.year # 2009, 年
now.month # 7, 月
now.day # 8, 日
now.hour # 22, 時間
now.minute # 59, 分
now.second # 0, 秒
now.microsecond # 688787, ミリ秒</pre>

<h3>タイムスタンプに変換する</h3>

<pre>from datetime import datetime
import calendar
now = datetime.now()
calendar.timegm(now.timetuple())</pre>

<h3>日時情報を整形した文字列を得る</h3>

<pre>from datetime import date
date(2009, 7, 9).strftime('%Y/%m/%d') # '2009/07/09'</pre>

<pre>from datetime import datetime
datetime(2009, 7, 8).strftime('%Y年%m月%d日 %H時%M分') # '2009年07月08日 23時34分'</pre>

<pre>from datetime import datetime
import time
time.strftime('%Y-%M-%d', datetime.now().timetuple()) # '2009-07-08'</pre>

<h3>N日後、N日前の日付を得る</h3>

<p>timedeltaオブジェクトを使うことで簡単に求めることができます。
timedeltaオブジェクトは、週、日、時間、分、秒、ミリ秒を扱うことができます。</p>

<pre>now = datetime.now() # datetime.datetime(2009, 7, 8, 0, 19, 3, 861658)
now + timedelta(days=+1) # datetime.datetime(2009, 7, 7, 0, 19, 3, 861658), 翌日
now - timedelta(days=+1) # datetime.datetime(2009, 7, 9, 0, 19, 3, 861658), 前日</pre>

<h3>月初、月末日を取得する</h3>

<p>月初日はreplace関数を使って簡単に求めることができます。</p>

<pre>from datetime import datetime
import calendar
now = datetime.now() # datetime.datetime(2009, 7, 8, 0, 19, 3, 861658)
now.replace(day=1) # datetime.datetime(2009, 7, 1, 0, 19, 3, 861658), 日を１日に設定</pre>

<p>月末日はcalendarモジュールのmonthrange関数を使って求めます。</p>

<pre>from datetime import datetime
import calendar
now = datetime.now() # datetime.datetime(2009, 7, 8, 0, 19, 3, 861658)
range = calendar.monthrange(now.year, now.month) # (2, 31), calendar.monthrangeの返値は、(月の一日の曜日, 月の日数)
now.replace(day=range[1]) # datetime.datetime(2009, 7, 31, 0, 19, 3, 861658), 現在月の末日を設定</pre>

<h3>日付の大小比較</h3>

<pre>from datetime import datetime
now = datetime.now() # datetime.datetime(2009, 7, 8, 22, 59, 0, 688787)
yesterday = now + timedelta(days=+1)
now &gt; yesterday # True</pre>

<h2>２．dateutilを使ってみる</h2>

<p>pythonで日付関連の処理を行っていると、どうも痒いところに手が届いていないなと印象も持ちました。例を上げると、datetimeモジュールのtimedeltaオブジェクトでは年や月を扱うことができないため月跨ぎ、年跨ぎの処理を書かなければならない。また、ある期間の特定の曜日のみ抽出するといった場合、どうしても泥臭い処理を書かなければなりません。</p>

<p>pythonにはdateutilという拡張パッケージが提供されており、dateutilはその名の通り、日付関連の処理を抽象化した手段を提供してくれます。</p>

<p>実際に使用例を下記に示します。</p>

<h3>N年後、N月後処理</h3>

<pre>
from datetimeimport date
from dateutil.relativedelta import relativedelta
date(2008, 2, 29) + relativedelta(years=1) # datetime.date(2009, 2, 28)
date(2008, 2, 29) + relativedelta(years=1, days=1) # datetime.date(2009, 3, 1)
date(2009, 3, 1) - relativedelta(years=1, days=1)  #datetime.date(2008, 2, 29)</pre>

<pre>date(2008, 8, 29) - relativedelta(months=6, days=1) # datetime.date(2008, 2, 28)
date(2008, 8, 30) - relativedelta(months=6, days=1) # datetime.date(2008, 2, 28)
date(2008, 8, 31) - relativedelta(months=6, days=1)  #datetime.date(2008, 2, 28)
date(2008, 9, 1) - relativedelta(months=6, days=1) # datetime.date(2008, 2, 29)</pre>

<h3>特定期間内の特定曜日のみを取得する</h3>

<p>下記の例では、2007年1月1日〜2009年1月１日の期間で火曜日と木曜日の日付情報を取得しています。</p>

<pre>from dateutil import rrule
L = rrule.rrule(rrule.WEEKLY, byweekday=(TU,TH), dtstart=datetime(2007,1,1), until=datetime(2009,1,1))
[datetime.datetime(2007, 1, 2, 0, 0),
 datetime.datetime(2007, 1, 4, 0, 0),
 datetime.datetime(2007, 1, 9, 0, 0)
‥
]</pre>

<p>他にも様々な便利な機能がありますので、日付関連の操作にお困りの方は使ってみてはいかがでしょうか。
HP：<a href="http://labix.org/python-dateutil">python-dateutil</a></p>
]]></content:encoded>
			<wfw:commentRss>http://labo.opengroove.com/blog/2009/07/09/python%e3%81%a7%e3%81%ae%e6%97%a5%e4%bb%98%e9%96%a2%e9%80%a3%e5%87%a6%e7%90%86/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pythonで互換性を考えてJSONを扱うには</title>
		<link>http://labo.opengroove.com/blog/2009/07/08/python%e3%81%a7%e4%ba%92%e6%8f%9b%e6%80%a7%e3%82%92%e8%80%83%e3%81%88%e3%81%a6json%e3%82%92%e6%89%b1%e3%81%86%e3%81%ab%e3%81%af/</link>
		<comments>http://labo.opengroove.com/blog/2009/07/08/python%e3%81%a7%e4%ba%92%e6%8f%9b%e6%80%a7%e3%82%92%e8%80%83%e3%81%88%e3%81%a6json%e3%82%92%e6%89%b1%e3%81%86%e3%81%ab%e3%81%af/#comments</comments>
		<pubDate>Wed, 08 Jul 2009 09:00:11 +0000</pubDate>
		<dc:creator>morimoto</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[JSON]]></category>

		<guid isPermaLink="false">http://labo.opengroove.com/blog/?p=65</guid>
		<description><![CDATA[はじめまして。morimotoです。

「パイソン」と初めて聞いた時はストリートファイターの四天王の名前かと思ったのですが、彼の名は「バイソン」でした。バイソンさんうる覚えでごめんなさい。

今日はPythonのバージョンを気にせずにJSONを扱う方法を書きたいと思います。

JSONとは軽量のデータ交換フォーマットです。（詳しくは⇒こちら）

Python2.6からJSONモジュールが標準サポートになりました。

「PythonでJSONを扱っていて現在の環境のPythonが2.6以前だが、2.6以降にアップグレードするかもしれない。」
という状況の場合、下記の条件を満たせば何も悩まずに開発を進めることができます。



    Python2.6以降の場合は、標準サポートのjsonを使う
    Python2.6以前の場合は、元々のライブラリsimplejsonを使う



Python2.6以前の場合はsimplejsonをインストールする必要がありますので、バージョンおよび環境に応じたsimplejsonをインストールしてください。

jsonを扱いたいファイルの冒頭に以下のコードを追加します。


import sys
if sys.version_info[:2] >= (2, 6): # If using Python 2.6 or later
    import json
else:
    # % easy_install simplejson
    import simplejson as json


これで json.dumps() や json.loads() をバージョンに関係なく使うことができるようになります。

それでは、良い「PythonでJSONライフ」を。
]]></description>
			<content:encoded><![CDATA[<p>はじめまして。morimotoです。</p>

<p>「パイソン」と初めて聞いた時はストリートファイターの四天王の名前かと思ったのですが、彼の名は「バイソン」でした。バイソンさんうる覚えでごめんなさい。</p>

<p>今日はPythonのバージョンを気にせずにJSONを扱う方法を書きたいと思います。</p>

<p>JSONとは軽量のデータ交換フォーマットです。（詳しくは⇒<a target="_blank">こちら</a>）<br /></p>

<p>Python2.6からJSONモジュールが標準サポートになりました。</p>

<p>「PythonでJSONを扱っていて現在の環境のPythonが2.6以前だが、2.6以降にアップグレードするかもしれない。」<br />
という状況の場合、下記の条件を満たせば何も悩まずに開発を進めることができます。</p>

<p>
<ul>
    <li>Python2.6以降の場合は、標準サポートのjsonを使う</li>
    <li>Python2.6以前の場合は、元々のライブラリsimplejsonを使う</li>
</ul>
</p>

<p>Python2.6以前の場合はsimplejsonをインストールする必要がありますので、バージョンおよび環境に応じたsimplejsonをインストールしてください。</p>

<p>jsonを扱いたいファイルの冒頭に以下のコードを追加します。</p>

<pre>
import sys
if sys.version_info[:2] >= (2, 6): # If using Python 2.6 or later
    import json
else:
    # % easy_install simplejson
    import simplejson as json
</pre>

<p>これで json.dumps() や json.loads() をバージョンに関係なく使うことができるようになります。</p>

<p>それでは、良い「PythonでJSONライフ」を。</p>
]]></content:encoded>
			<wfw:commentRss>http://labo.opengroove.com/blog/2009/07/08/python%e3%81%a7%e4%ba%92%e6%8f%9b%e6%80%a7%e3%82%92%e8%80%83%e3%81%88%e3%81%a6json%e3%82%92%e6%89%b1%e3%81%86%e3%81%ab%e3%81%af/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
