日付処理
後で書きます(ぺこり)
日付型・日付文字列型・UnixTime整数型 相互変換
日付のイテレート
データが年月日別に管理され、その中から期間を指定して分析を行いたいことはよくある。
期間を文字列で指定すると、1日ずつ順番に日付を返すジェネレータがあると便利。
主な使い方
- 入力文字列
<Dates>
- 指定方法
<Date> ::= “YYYYMMDD”
形式の日付文字列<Dates>::= <Date> | <Date>-<Date> | <Dates>,<Dates>
- 意味
- ハイフン区切り「
YYYYMMDD-YYYYMMDD
」は、期間を表す - カンマ区切り「
YYYYMMDD,YYYYMMDD
」は、別々の2日を表す
- 返値
YYYYMMDD
の文字列を指定された順に返すIterator
(例) 入力: 20150101-20150331,20150701,20150801 出力: 20150101, 20150102, 20150103, ..., 20150331, 20150701, 20150801
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 31 32 33 34 35 36 37 |
from datetime import datetime from dateutil.relativedelta import relativedelta # 日単位でのイテレート ------------------------------------ # 補助関数 def _generate_between_date(start_date_str, stop_date_str): start_date = datetime.strptime(start_date_str, '%Y%m%d' ) stop_date = datetime.strptime(stop_date_str, '%Y%m%d' ) while start_date < = stop_date: yield start_date.strftime( '%Y%m%d' ) start_date + = relativedelta(days = 1 ) # こちらを使う def date_sequence_generator(dates_str): for date_str in dates_str.split( ',' ): if '-' in date_str: for date in _generate_between_date( * date_str.split( '-' )): yield date else : yield date_str # 月単位でのイテレート ----------------------------------- def _generate_between_month(start_month_str, stop_month_str): start_month = datetime.strptime(start_month_str, '%Y%m' ) stop_month = datetime.strptime(stop_month_str, '%Y%m' ) while start_month < = stop_month: yield start_month.strftime( '%Y%m' ) start_month + = relativedelta(months = 1 ) def month_sequence_generator(months_str): for month_str in months_str.split( ',' ): if '-' in month_str: for month in _generate_between_month( * month_str.split( '-' )): yield month else : yield month_str |
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 31 |
use DateTime; class DateIterator { function iterateDate( $target_dates ) { $comma_explodeds = explode ( ',' , $target_dates ); foreach ( $comma_explodeds as $cma ) { $hyphen_explodeds = explode ( '-' , $cma ); if ( count ( $hyphen_explodeds ) === 1) { yield $cma ; } elseif ( count ( $hyphen_explodeds ) === 2) { $d = DateTime::createFromFormat( 'Ymd' , $hyphen_explodeds [0]); $t = DateTime::createFromFormat( 'Ymd' , $hyphen_explodeds [1]); if ( $d === false || $t === false) { throw new \UnexpectedValueException( 'iterateDate parse date' ); } while ( $d <= $t ) { yield $d ->format( 'Ymd' ); $d ->modify( '+1 day' ); } } else { throw new \UnexpectedValueException( 'iterateDate hyphen' ); } } } } |
KotlinではGeneratorの機能がまだexperimentalなので、Listを返すようにする。
また、Java8より導入されたLocalDateTimeを利用する。
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 31 32 33 34 |
import java.time.LocalDate import java.time.format.DateTimeFormatter import java.time.format.ResolverStyle fun String .iterateDate(): List< String > { val formatter = DateTimeFormatter.ofPattern( "uuuuMMdd" ).withResolverStyle(ResolverStyle.STRICT) val dateList = mutableListOf< String >() this .split( ',' ).forEach { val hyphenSplit = it.split( '-' ) when (hyphenSplit.size) { 1 -> { // パースできるかだけ確認 LocalDate.parse(hyphenSplit[ 0 ], formatter) dateList += hyphenSplit[ 0 ] } 2 -> { var curDate = LocalDate.parse(hyphenSplit[ 0 ], formatter) val tgtDate = LocalDate.parse(hyphenSplit[ 1 ], formatter) while (curDate <= tgtDate) { dateList += curDate.format(formatter) curDate = curDate.plusDays( 1 ) } } else -> { throw IllegalArgumentException( "Can't iterate date: %s" .format(it)) } } } return dateList } |