投稿/コメントを表示します。

藤本 博子さんの投稿

(投稿ID: 5362)

日付データ(1000マイクロ秒)毎にtimedeltaオブジェクトで加算した日時データを(1)CSV、textファイルへ書き込み (2)書き込み・保存したCSVデータを読み込み、Excelへ出力を試してみました。
■結論
・pythonで日付データを生成し、CSVへ書き込み、保存したファイルを開いた場合
生成した日付データの表示形式が秒単位以下の細かい単位になると、見た目が誤変換のように見えました。
日付データをmicroseconds単位で書き込みしたCSVを開くと、00:00.0 という表示形式になりました。
しかし、pythonで生成した日付データは、正しい内容でCSVに保存されており、CSV→Excelにpntyonで生成した日付データの内容で書き出せることを確認しました。
(ISO8601形式? yyyy-mm-dd hh:mm:ss.SSSSSS (例)2022-03-01 10:00:00.016000)
・textファイルでpythonのmicroseconds単位の日付データを書き込んだ場合、表示形式はpythonで生成した書式形式と同じでした。(事前に文字列に変換しないとtextに書き込みできませんが)
結果は問題なかったので、自分的には、慌てずに対処しようと思いました。という、どうしようもないオチです…
実際に自分で確かめたこと、また小川先生にリライトしてもらったcsv.Dictwriter,Dictreaderや辞書型への変換のバリエーションなど、自分のケースで適用できたことはよかったと思いました。

一応試したこと
・CSVへ書き出すときに、日付データをstrftimeメソッドで文字列に予め変換しても、マイクロ秒の日付データは、CSVでは、00:00.0という書式のままでした。
・また、CSVへ書き込む時に表示形式を指定できるのか方法を探しましたがみつかりませんでした。

■確認した背景
実務で日付データを扱うVBAの相談を受けたことがありました。(日付データは、秒単位、ミリ秒と単位が細かい)
作業内容は、参照元のCSVファイルから、指定された開始日時、終了時間に該当する部分だけ、所定のExcelファイルに書き込む、その際、参照元(csv)と書き込み先(Excel)の行見出しの順序は一致しない)というものです。
pythonでも同じ作業をすることができるか、確認したいと思いました。

■確認したこと:
「1」pythonでCSVに書き込みした場合
timedeltaオブジェクトの引数単位別加算して50行のデータを生成。CSVで日付データがどう表示されるのか確認しました。

timedelta(引数) csv書出(見た目上) データの中身  
minutes=1  2022/3/1 10:01   2022/3/1 10:01:00 ・・・分単位であれば、誤変換と間違う混乱は無し
seconds=1  2022/3/1 10:00   2022/3/1 10:00:01 ・・・見た目上、秒単位が表示されない。実際のデータの中身は問題無し
microseconds1=1000 00:00.0   2022/3/1 10:0:0.001 ・・・見た目上、誤変換と見間違う。でも、実際のデータの中身は問題無し(ユーザー定義が必要 yyyy/m/d h:m:s.000)
notepad(txtファイル)から開くと、日付データは正しく表示される。 例:2022-03-01 10:00:00.001000 

float型の表示
元データ(小数点17桁)→ 書出先のCSV:小数点15桁まで表示(16桁目切捨)
notepad(txtファイル)から開くと、元データと同じく小数点16桁まで表示される

「2」pythonから書き込んだCSVファイルを読み込み、Excelへ書き込んだ場合
日付データ → 元データと同じマイクロセカンド(6桁表示)2022-03-01 10:00:00.002000
float型 → 小数点16桁まで表示(文字列型になってましたが)

「3」pythonで、textファイルへ書出した場合
・textへ書き込む場合、事前に文字列に変換が必要となります。writeメソッド(文字列) writelines()メソッドもあるようですが・・・
書出し内容が日付データ、数値の場合は、文字列に変換する必要があるので、CSVで書き込みした方がよいと思いました。
・表示される日付データの書式、float型小数点の桁数は、pythonで生成した元データと同じ桁数になりました。
import csv
import random
from datetime import datetime,timedelta

'''
「1」サンプルデータの作成
先頭列 :日時データ 1000マイクロ秒毎に加算(年・月・日 時間:分:秒.000000マイクロ秒)
行見出 :アイテムa アイテムb アイテムc ・・・
行データ:ランダムの数値 float_a,float_b,float_c
「2」辞書の形式で保存 {key(先頭列日時データ):{item_a:float_a,item_b:float_b,item_c:float_c}
2022-03-01 10:00:00.001000:{'a': 0.18047978517289842, 'b': 0.8172327998831116, 'c': 0.2295418854425827}
'''
dic = {}
categories = ["a","b","c"]#見出し行 item名
dt = datetime(2022,3,1,10,0,0)#日付生成データ開始時間

for c in range(0,50):#50行データを生成
    dt = dt + timedelta(microseconds=1000)#日付は1000マイクロ秒毎に加算
    # dt_str = dt.strftime("%Y-%m-%d %H:%M:%S.%f")
    dic_num = {}
    for n,ls in enumerate(categories):
        num = random.random()
        #{a:num1,b:num2,c:nmu3}の要素を作成する辞書
        dic_num.update({ls:num})
        # print(dic_num)
    # 辞書(キー)date:要素{a:num1,b:num2,c:nmu3} の辞書を作成する
    dic[dt] = dic_num

'''
「3」「2」の辞書データを、csvに書き出すためのリストオブジェクトを作成する。
辞書のアイテムをコピーして、新しい辞書に保存→その辞書に、key(先頭列日時データ)の要素も一緒にリスト化する。
date_type_list {'a': 0.18047978517289842, 'b': 0.8172327998831116, 'c': 0.2295418854425827, 'date': '2022-03-01 10:00:00.001000'}
'''
date_type_list = []
for key,value in dic.items():
    new_dic = value.copy()
    new_dic["date"] = key
    date_type_list.append(new_dic)

'''
「4」「3」のリストのデータを、csv.Dictwriterでcsvファイルに書き出す。
見出行の順序は、date,item_a,item_b,item_cの順番に書き出す。→小川先生のリライトをみて、すごい!と思った。
'''
with open("test_data_microsecond.csv",newline="",mode="w",encoding="utf-8") as f:
    field_names = ("date","a","b","c")
    writer = csv.DictWriter(f,fieldnames=field_names)
    writer.writeheader()
    writer.writerows(date_type_list)

'''
「5」指定された開始時刻・終了時刻に該当した部分のみ、参照元csvから書出先のEXCLに転記する。
書き込みする対象
start_time = "2022-03-01 10:00:00.015000" 以降
end_time = "2022-03-01 10:00:00.031000" より前のデータ
'''
import csv
import openpyxl

'''
csvのデータを辞書形式で読み込み、リストを作成する 
[{'date': '2022-03-01 10:00:00.001000', 'item_a': , 'b': '0.2922968193072939', 'c': '0.9474747444571356'}… ]
'''
date_type_list = []
with open("test_data_microsecond.csv",mode="r",encoding="utf-8") as f:
    for row in csv.DictReader(f):
        date_type_list.append(row)

'''
エクセルへ書き出す為の辞書を作成する {key(先頭列日時データ):{item_a:float_a,item_b:float_b,item_c:float_c}
'''
dic = {}
for val in date_type_list:
    key = val["date"]
    tmp_dic = {}
    for k,v in val.items():
        if k != "date":
            tmp_dic[k] = v
    print(tmp_dic)
    dic[key] = tmp_dic

for k,v in dic.items():
    print(k,v,sep="☆")

'''
エクセルへ書き出す時間を変数に格納する
'''
start_time = "2022-03-01 10:00:00.015000"
end_time = "2022-03-01 10:00:00.031000"

'''
エクセルへ書き出す時間を変数に格納する
作業したエクセルファイル用のPath変数をつくる
エクセルの所定フォーマットの見出行の順序は、a,c,b (参照元csvの見出し行は、a,b,c)
'''
wb = openpyxl.load_workbook("test_data_microsecond.xlsx")
wb_mod = "test_data_microsecond_mod.xlsx"
sh = wb["data"]
items_list = []

#転記先の見出行のリスト 
for row in sh.iter_rows(min_row=1,min_col=2,max_row=1,max_col=4):
    for r in row:
        items_list.append(r.value)
print(items_list)

'''
csvデータから読み取ったデータから、指定した開始時間・終了時間の間のデータをエクセルファイルに書出す。
書出し先の項目の順序は、読み取りデータとは違うため、一致した項目の列に書出する。最後に編集用エクセルファイルに保存する。
'''
cnt = 2
#key:date v:itemsとdataのvalue
for d,val in dic.items():
    if start_time < d < end_time:#日付データが開始時間・終了時間の間
        sh.cell(row=cnt,column=1).value = d
        print(val)
        for k,v in val.items():
            for c, i in enumerate(items_list):
                if k == i:#辞書のkey (項目名 a,b,c) と、転記先エクセルの項目名(a,c,b)が一致したら、float型のデータを書出す
                    sh.cell(row=cnt,column=c+2).value = v
        cnt += 1
wb.save(wb_mod)

'''
テキストファイルへ書出し
テキストファイルへ書出す場合、文字列への変換が必要。
書出し内容が日付データ、数値の場合は、CSVファイルへ書き出した方がよいと思う。
'''
import random
from datetime import datetime,timedelta
from pathlib import Path
import csv

dic = {}
categories = ["a","b","c"]
dt = datetime(2022,3,1,10,0,0)
# 日時・項目・数値のデータを作成
for c in range(0,50):
    dt = dt + timedelta(microseconds=1000)
    dt_str = dt.strftime("%Y-%m-%d %H:%M:%S.%f")
    dic_num = {}#初期化
    for n,ls in enumerate(categories):
        num = random.random()
        #{a:num1,b:num2,c:nmu3}の要素を作成する辞書
        dic_num.update({ls:num})
    # 辞書(キー)date:要素{a:num1,b:num2,c:nmu3} の辞書を作成する
    dic[dt_str] = dic_num

date_list = []
for key,val in dic.items():
    tmp_list = []
    for k,v in val.items():
        tmp_list.append(str(v))
    tmp_list.insert(0,key)
    date_list.append(tmp_list)

'''
pythonで作成したデータをtextファイルへ書出し .joinメソッドで改行する
'''
#text書出し用の見出し行のリスト
midashi = categories.copy()
print(id(midashi),id(categories))
midashi.insert(0,"date")

mod_path = Path("./output.txt")
with mod_path.open(mode="w",encoding="utf-8") as f:
    f.write("\t".join(midashi)+"\n")#見出し行 
    for row in date_list:
        r = map(str,row)#文字列で結合のため、map関数
        row_data = "\t".join(r)
        f.write(row_data+"\n")

'''
書出したtextファイルを読み込んで、print関数で出力してみる
'''
read_path = Path("./output.txt")
with read_path.open(encoding="utf-8") as f:
    read_row = f.read()
    print(read_row)
    print(type(read_row))# class "str"

w_path = Path("./output_2.txt")

with mod_path.open(mode="w",encoding="utf-8") as f:
    f.write("\t".join(midashi)+"\n")#見出し行 
    for row in date_list:
        r = map(str,row)#文字列で結合のため、map関数
        row_data = "\t".join(r)
        f.write(row_data+"\n")

2022/08/12 21:30