diff --git a/sohstationviewer/controller/core/time_tmp.py b/sohstationviewer/controller/core/time_tmp.py new file mode 100644 index 0000000000000000000000000000000000000000..74e9df879818ee984dd65266c0652cb780ec2e51 --- /dev/null +++ b/sohstationviewer/controller/core/time_tmp.py @@ -0,0 +1,1132 @@ +""" +Processing time functions that are derived exactly from qpeek/logpeek +""" +from time import gmtime, localtime, sleep, strftime, time +from struct import pack, unpack +from sohstationviewer.controller.core.utils import intt, floatt, rtnPattern +from obspy import UTCDateTime + +# First day of the month for each non-leap year month MINUS 1. This will get +# subtracted from the DOY, so a DOY of 91, minus the first day of April 90 +# (91-90) will leave the 1st of April. The 365 is the 1st of Jan of the next +# year. +PROG_FDOM = (0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365) +# Max days per month. +PROG_MAXDPMNLY = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) +PROG_MAXDPMLY = (0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) +# Not very friendly to other countries, but... +PROG_CALMON = ("", "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", + "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", + "DECEMBER") +PROG_CALMONS = ("", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", + "SEP", "OCT", "NOV", "DEC") +PROG_MONNUM = {"JAN": 1, "FEB": 2, "MAR": 3, "APR": 4, "MAY": 5, "JUN": 6, + "JUL": 7, "AUG": 8, "SEP": 9, "OCT": 10, "NOV": 11, "DEC": 12} +# For use with the return of the calendar module weekday function. +PROG_DOW = ("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun") + +def formatTime(parent, time, dateMode, timeMode=None): + """ + timeMode + """ + # print((parent, time, dateMode, timeMode)) + if isinstance(time, UTCDateTime): + t = time + else: + t = UTCDateTime(time) + + # https://docs.python.org/3/library/datetime.html# + # strftime-and-strptime-format-codes + format = '' + if dateMode == 'YYYY-MM-DD': + format = '%Y-%m-%d' + elif dateMode == 'YYYYMMDD': + format = '%Y%m%d' + elif dateMode == 'YYYY:DOY': + format = '%Y:%j' + elif parent is not None: + parent.displayTrackingInfo("not defined format:'%s'" % dateMode, + "error") + if timeMode == 'HH:MM:SS': + format += " %H:%M:%S" + # print("newTime:", t) + + ret = t.strftime(format) + + return ret + +# +# ####################### +# # BEGIN: getGMT(Format) +# # LIB:getGMT():2015.007 +# # Gets the time in various forms from the system. +# def getGMT(Format): +# # YYYY:DOY:HH:MM:SS (GMT) +# if Format == 0: +# return strftime("%Y:%j:%H:%M:%S", gmtime(time())) +# # YYYYDOYHHMMSS (GMT) +# elif Format == 1: +# return strftime("%Y%j%H%M%S", gmtime(time())) +# # YYYY-MM-DD (GMT) +# elif Format == 2: +# return strftime("%Y-%m-%d", gmtime(time())) +# # YYYY-MM-DD HH:MM:SS (GMT) +# elif Format == 3: +# return strftime("%Y-%m-%d %H:%M:%S", gmtime(time())) +# # YYYY, MM and DD (GMT) returned as ints +# elif Format == 4: +# GMT = gmtime(time()) +# return (GMT[0], GMT[1], GMT[2]) +# # YYYY-Jan-01 (GMT) +# elif Format == 5: +# return strftime("%Y-%b-%d", gmtime(time())) +# # YYYYMMDDHHMMSS (GMT) +# elif Format == 6: +# return strftime("%Y%m%d%H%M%S", gmtime(time())) +# # Reftek Texan (year-1984) time stamp in BBBBBB format (GMT) +# elif Format == 7: +# GMT = gmtime(time()) +# return pack(">BBBBBB", (GMT[0] - 1984), 0, 1, GMT[3], GMT[4], GMT[5]) +# # Number of seconds since Jan 1, 1970 from the system. +# elif Format == 8: +# return time() +# # YYYY-MM-DD/DOY HH:MM:SS (GMT) +# elif Format == 9: +# return strftime("%Y-%m-%d/%j %H:%M:%S", gmtime(time())) +# # YYYY-MM-DD/DOY (GMT) +# elif Format == 10: +# return strftime("%Y-%m-%d/%j", gmtime(time())) +# # YYYY, DOY, HH, MM, SS (GMT) returned as ints +# elif Format == 11: +# GMT = gmtime(time()) +# return (GMT[0], GMT[7], GMT[3], GMT[4], GMT[5]) +# # HH:MM:SS (GMT) +# elif Format == 12: +# return strftime("%H:%M:%S", gmtime(time())) +# # YYYY:DOY:HH:MM:SS (LT) +# elif Format == 13: +# return strftime("%Y:%j:%H:%M:%S", localtime(time())) +# # HHMMSS (GMT) +# elif Format == 14: +# return strftime("%H%M%S", gmtime(time())) +# # YYYY-MM-DD (LT) +# elif Format == 15: +# return strftime("%Y-%m-%d", localtime(time())) +# # YYYY-MM-DD/DOY Day (LT) +# elif Format == 16: +# return strftime("%Y-%m-%d/%j %A", localtime(time())) +# # MM-DD (LT) +# elif Format == 17: +# return strftime("%m-%d", localtime(time())) +# # YYYY, MM and DD (LT) returned as ints +# elif Format == 18: +# LT = localtime(time()) +# return (LT[0], LT[1], LT[2]) +# # YYYY-MM-DD/DOY HH:MM:SS Day (LT) +# elif Format == 19: +# return strftime("%Y-%m-%d/%j %H:%M:%S %A", localtime(time())) +# # Return GMT-LT difference. +# elif Format == 20: +# Secs = time() +# LT = localtime(Secs) +# GMT = gmtime(Secs) +# return dt2Timeymddhms(-1, LT[0], -1, -1, LT[7], LT[3], LT[4], +# LT[5]) - dt2Timeymddhms(-1, GMT[0], -1, -1, +# GMT[7], GMT[3], GMT[4], +# GMT[5]) +# # YYYY-MM-DD/DOY HH:MM:SS (LT) +# elif Format == 21: +# return strftime("%Y-%m-%d/%j %H:%M:%S", localtime(time())) +# # YYYY-MM-DD HH:MM:SS (LT) +# elif Format == 22: +# return strftime("%Y-%m-%d %H:%M:%S", localtime(time())) +# return "" +# # END: getGMT +# +# #################################### +# # BEGIN: dt2Timeverify(Which, Parts) +# # FUNC:dt2Timeverify():2015.048 +# # This could figure out what to check just by passing [Y,M,D,D,H,M,S], but +# # that means the splitters() in dt2Time would need to work much harder to +# # make sure all of the Parts were there, thus it needs a Which value. +# +# +# def dt2Timeverify(Which, Parts): +# if Which.startswith("ydhms"): +# YYYY = intt(Parts[0]) +# MMM = -1 +# DD = -1 +# DOY = intt(Parts[1]) +# HH = intt(Parts[2]) +# MM = intt(Parts[3]) +# SS = floatt(Parts[4]) +# elif Which.startswith("ymdhms") or Which.startswith("xymdhms"): +# YYYY = intt(Parts[0]) +# MMM = intt(Parts[1]) +# DD = intt(Parts[2]) +# DOY = -1 +# HH = intt(Parts[3]) +# MM = intt(Parts[4]) +# SS = floatt(Parts[5]) +# elif Which.startswith("hms"): +# YYYY = -1 +# MMM = -1 +# DD = -1 +# DOY = -1 +# HH = intt(Parts[0]) +# MM = intt(Parts[1]) +# SS = floatt(Parts[2]) +# if YYYY != -1 and (YYYY < 1000 or YYYY > 9999): +# return (1, "RW", "Bad year value: %d" % YYYY, 2, "") +# # Normally do the normal checking. +# if Which.startswith("x") is False: +# if MMM != -1 and (MMM < 1 or MMM > 12): +# return (1, "RW", "Bad month value: %d" % MMM, 2, "") +# if DD != -1: +# if DD < 1 or DD > 31: +# return (1, "RW", "Bad day value: %d" % DD, 2, "") +# if YYYY % 4 != 0: +# if DD > PROG_MAXDPMNLY[MMM]: +# return (1, "RW", "Too many days for month %d: %d" % +# (MMM, DD), 2, "") +# elif YYYY % 100 != 0 or YYYY % 400 == 0: +# if DD > PROG_MAXDPMLY[MMM]: +# return (1, "RW", "Too many days for month %d: %d" % +# (MMM, DD), 2, "") +# else: +# if DD > PROG_MAXDPMNLY[MMM]: +# return (1, "RW", "Too many days for month %d: %d" % +# (MMM, DD), 2, "") +# if DOY != -1: +# if DOY < 1 or DOY > 366: +# return (1, "RW", "Bad day of year value: %d" % DOY, 2, "") +# if YYYY % 4 != 0 and DOY > 365: +# return (1, "RW" "Too many days for non-leap year: %d" % DOY, +# 2, "") +# if HH < 0 or HH >= 24: +# return (1, "RW", "Bad hour value: %d" % HH, 2, "") +# if MM < 0 or MM >= 60: +# return (1, "RW", "Bad minute value: %d" % MM, 2, "") +# if SS < 0 or SS >= 60: +# return (1, "RW", "Bad seconds value: %06.3f" % SS, 2, "") +# # "x" checks. +# # Here if Which starts with "x" then it is OK if month and day values are +# # missing. This is for checking an entry like 2013-7 for example. If the +# # portion of the date(/time) that was passed looks OK then (0,) will be +# # returned. If it is something like 2013-13 then that will be bad. +# else: +# # If the user entered just the year, then we are done, etc. +# if MMM != -1: +# if MMM < 1 or MMM > 12: +# return (1, "RW", "Bad month value: %d" % MMM, 2, "") +# if DD != -1: +# if DD < 1 or DD > 31: +# return (1, "RW", "Bad day value: %d" % DD, 2, "") +# if YYYY % 4 != 0: +# if DD > PROG_MAXDPMNLY[MMM]: +# return (1, "RW", "Too many days for month %d: %d" % +# (MMM, DD), 2, "") +# elif YYYY % 100 != 0 or YYYY % 400 == 0: +# if DD > PROG_MAXDPMLY[MMM]: +# return (1, "RW", "Too many days for month %d: %d" % +# (MMM, DD), 2, "") +# else: +# if DD > PROG_MAXDPMNLY[MMM]: +# return (1, "RW", "Too many days for month %d: %d" % +# (MMM, DD), 2, "") +# if DOY != -1: +# if DOY < 1 or DOY > 366: +# return (1, "RW", "Bad day of year value: %d" % DOY, 2, +# "") +# if YYYY % 4 != 0 and DOY > 365: +# return (1, "RW" +# "Too many days for non-leap year: %d" % DOY, +# 2, "") +# if HH != -1: +# if HH < 0 or HH >= 24: +# return (1, "RW", "Bad hour value: %d" % HH, 2, "") +# if MM != -1: +# if MM < 0 or MM >= 60: +# return (1, "RW", "Bad minute value: %d" % MM, 2, +# "") +# # Checking these special values are usually from user +# # input and are date/time values and not timing values, +# # so the seconds part here will just be an int. +# if SS != -1: +# if SS < 0 or SS >= 60: +# return (1, "RW", "Bad seconds value: %d" % SS, +# 2, "") +# return (0,) +# +# ################################## +# # BEGIN: dt2Timeydoy2md(YYYY, DOY) +# # FUNC:dt2Timeydoy2md():2013.030 +# # Does no values checking, so make sure you stuff is in one sock before +# # coming here. +# +# def dt2Timeydoy2md(YYYY, DOY): +# if DOY < 32: +# return 1, DOY +# elif DOY < 60: +# return 2, DOY - 31 +# if YYYY % 4 != 0: +# Leap = 0 +# elif YYYY % 100 != 0 or YYYY % 400 == 0: +# Leap = 1 +# else: +# Leap = 0 +# # Check for this special day. +# if Leap == 1 and DOY == 60: +# return 2, 29 +# # The PROG_FDOM values for Mar-Dec are set up for non-leap years. If it is +# # a leap year and the date is going to be Mar-Dec (it is if we have made it +# # this far), subtract Leap from the day. +# DOY -= Leap +# # We start through PROG_FDOM looking for dates in March. +# Month = 3 +# for FDOM in PROG_FDOM[4:]: +# # See if the DOY is less than the first day of next month. +# if DOY <= FDOM: +# # Subtract the DOY for the month that we are in. +# return Month, DOY - PROG_FDOM[Month] +# Month += 1 +# # If anything goes wrong... +# return 0, 0 +# ###################################### +# # BEGIN: dt2Timeymd2doy(YYYY, MMM, DD) +# # FUNC:dt2Timeymd2doy():2013.030 +# +# +# def dt2Timeymd2doy(YYYY, MMM, DD): +# if YYYY % 4 != 0: +# return (PROG_FDOM[MMM] + DD) +# elif (YYYY % 100 != 0 or YYYY % 400 == 0) and MMM > 2: +# return (PROG_FDOM[MMM] + DD + 1) +# else: +# return (PROG_FDOM[MMM] + DD) +# ################################################################## +# # BEGIN: dt2Timeymddhms(outFormat, YYYY, MMM, DD, DOY, HH, MM, SS) +# # FUNC:dt2Timeymddhms():2018.235 +# # The general-purpose time handler for when the time is already split up into +# # it's parts. +# # Make MMM, DD -1 if passing DOY and DOY -1 if passing MMM, DD. +# +# +# def dt2Timeymddhms(outFormat, YYYY, MMM, DD, DOY, HH, MM, SS): +# global Y2EPOCH +# # Returns a float Epoch is SS is a float, otherwise an int value. +# if outFormat == -1: +# Epoch = 0 +# if YYYY < 70: +# YYYY += 2000 +# if YYYY < 100: +# YYYY += 1900 +# try: +# Epoch = Y2EPOCH[YYYY] +# except KeyError: +# for YYY in range(1970, YYYY): +# if YYY % 4 != 0: +# Epoch += 31536000 +# elif YYY % 100 != 0 or YYY % 400 == 0: +# Epoch += 31622400 +# else: +# Epoch += 31536000 +# Y2EPOCH[YYYY] = Epoch +# if DOY == -1: +# DOY = dt2Timeymd2doy(YYYY, MMM, DD) +# return Epoch + ((DOY - 1) * 86400) + (HH * 3600) + (MM * 60) + SS +# +# ########################################################## +# # BEGIN: dtHoursFromNow(ToFormat, outFormat, dateTime, TZ) +# # FUNC:dtHoursFromNow():2018.264 +# # Takes in a time (presumably in the future) and returns the decimal hours +# # from now until then. +# # ToFormat is the format of the time we are going to. +# # outFormat is how to format the return time, "H" for decimal hours, or "H:M" +# # for HH:MM (no seconds). +# # TZ is either "GMT" or "LT" pertaining to the input dateTime. +# # The current time it uses (in YYYY:DOY:HH:MM:SS) is also returned. +# # (decimal hours, current time used) +# +# +# def dtHoursFromNow(ToFormat, outFormat, dateTime, TZ): +# InEpoch = dt2Time(ToFormat, -1, dateTime) +# if TZ == "GMT": +# NowdateTime = getGMT(0) +# elif TZ == "LT": +# NowdateTime = getGMT(13) +# NowEpoch = dt2Time(11, -1, NowdateTime) +# Diff = InEpoch - NowEpoch +# if outFormat == "H": +# return ("%.2f hours" % (Diff / 3600.0), NowdateTime) +# elif outFormat == "H:M": +# H = Diff / 3600.0 +# M = int((H - int(H)) * 60.0) +# H = int(H) +# # Rounding may cause this. +# if M > 59: +# H += 1 +# M = M - 60 +# return ("%02d:%02d" % (H, M), NowdateTime) +# return ("0.00", "0000:000:00:00:00") +# ############################ +# # BEGIN: dt2DateDiff(D1, D2) +# # FUNC:dt2DateDiff():2018.238 +# # Takes two dates in YYYY-MM-DD format and returns the number of whole days +# # between them. Dates must be proper format or there will be crashing. +# # Returned is D2-D1, so D2 should be later than D1, but doesn't have to be. +# +# +# def dt2DateDiff(D1, D2): +# Parts = D1.split("-") +# D1Y = int(Parts[0]) +# D1M = int(Parts[1]) +# D1D = int(Parts[2]) +# Parts = D2.split("-") +# D2Y = int(Parts[0]) +# D2M = int(Parts[1]) +# D2D = int(Parts[2]) +# # Pick off the easy one. +# if D1Y == D2Y and D1M == D2M: +# return D2D - D1D +# # Almost easy. +# elif D1Y == D2Y: +# D1Doy = dt2Timeymd2doy(D1Y, D1M, D1D) +# D2Doy = dt2Timeymd2doy(D2Y, D2M, D2D) +# return D2Doy - D1Doy +# else: +# # The full monty. +# D1E = dt2Timeymddhms(-1, D1Y, D1M, D1D, -1, 0, 0, 0) +# D2E = dt2Timeymddhms(-1, D2Y, D2M, D2D, -1, 0, 0, 0) +# return int((D2E - D1E) / 86400) +# # END: dt2Time +# +# ############################################################### +# # BEGIN: dt2Time(inFormat, outFormat, dateTime, verify = False) +# # LIB:dt2Time():2018.270 +# # inFormat = -1 = An Epoch has been passed. +# # 0 = Figure out what was passed. +# # other = Use if the caller knows exactly what they have. +# # outFormat = -1 = Epoch +# # 0 = Y M D D H M S.s +# # 1 = Uses OPTdateFormatRVar value. +# # other = whatever supported format the caller wants +# # The format of the time will always be HH:MM:SS.sss. +# # Returns (0/1, <answer or error msg>) if verify is True, or <answer/0/""> +# # if verify is False. Confusing, but most of the calls are with verify set +# # to False, and having to always put [1] at the end of each call was getting +# # old fast. This probably will cause havoc if there are other errors like +# # passing date/times that cannot be deciphered, or passing bad In/outFormat +# # codes (just "" will be returned), but that's the price of progress. You'll +# # still have to chop off the milliseconds if they are not wanted ([:-4]). +# # Needs option_add(), intt(), floatt(), rtnPattern() +# +# +# def dt2Time(inFormat, outFormat, dateTime, dateFormat, verify=False): +# """ +# +# :param inFormat: +# :param outFormat: +# :param dateTime: +# :param dateFormat: YYYY:DOY, YYYY-MM-DD or YYYYMMMDD +# :param verify: +# :return: +# """ +# global Y2EPOCH +# if inFormat == -1: +# YYYY = 1970 +# while True: +# if YYYY % 4 != 0: +# if dateTime >= 31536000: +# dateTime -= 31536000 +# else: +# break +# elif YYYY % 100 != 0 or YYYY % 400 == 0: +# if dateTime >= 31622400: +# dateTime -= 31622400 +# else: +# break +# else: +# if dateTime >= 31536000: +# dateTime -= 31536000 +# else: +# break +# YYYY += 1 +# DOY = 1 +# while dateTime >= 86400: +# dateTime -= 86400 +# DOY += 1 +# HH = 0 +# while dateTime >= 3600: +# dateTime -= 3600 +# HH += 1 +# MM = 0 +# while dateTime >= 60: +# dateTime -= 60 +# MM += 1 +# SS = dateTime +# MMM, DD = dt2Timeydoy2md(YYYY, DOY) +# else: +# dateTime = dateTime.strip().upper() +# # The caller will have to decide if these returns are OK or not. +# if len(dateTime) == 0: +# if outFormat - 1: +# if verify is False: +# return 0.0 +# else: +# return (0, 0.0) +# elif outFormat == 0: +# if verify is False: +# return 0, 0, 0, 0, 0, 0, 0.0 +# else: +# return (0, 0, 0, 0, 0, 0, 0, 0.0) +# elif inFormat == 5: +# if verify is False: +# return "00:00:00:00" +# else: +# return (0, "00:00:00:00") +# else: +# if verify is False: +# return "" +# else: +# return (0, "") +# # The overall goal of the decode will be to get the passed string time +# # into YYYY, MMM, DD, DOY, HH, MM integers and SS.sss float values +# # then proceed to the encoding section ready for anything. +# # These will try and figure out what the date is between the usual +# # formats. +# # Checks first to see if the date and time are together (like with a :) +# # or if there is a space between them. +# if inFormat == 0: +# Parts = dateTime.split() +# if len(Parts) == 1: +# # YYYY:DOY:... - 71:2 will pass. +# if dateTime.find(":") != -1: +# Parts = dateTime.split(":") +# # There has to be something that looks like YYYY:DOY. +# if len(Parts) >= 2: +# inFormat = 11 +# # YYYY-MM-DD:HH:... +# # If there was only one thing and there are dashes then it +# # could be Y-M-D or Y-M-D:H:M:S. Either way there must be 3 +# # parts. +# elif dateTime.find("-") != -1: +# Parts = dateTime.split("-") +# if len(Parts) == 3: +# inFormat = 21 +# # YYYYMMMDD:HH:... - 68APR3 will pass. +# elif (dateTime.find("A") != -1 or dateTime.find("E") != -1 or +# dateTime.find("O") != -1 or dateTime.find("U") != -1): +# inFormat = 31 +# # YYYYDOYHHMMSS - Date/time must be exactly like this. +# elif len(dateTime) == 13: +# if rtnPattern(dateTime) == "0000000000000": +# inFormat = 41 +# # YYYYMMDDHHMMSS - Date/time must be exactly like this. +# elif len(dateTime) == 14: +# if rtnPattern(dateTime) == "00000000000000": +# inFormat = 51 +# # (There is no 1974JAN23235959 that I know of, but the elif for +# # it would be here. -> +# # There were two parts. +# else: +# Date = Parts[0] +# Time = Parts[1] +# # YYYY:DOY HH:MM... +# if Date.find(":") != -1: +# # Must have at least YYYY:DOY. +# Parts = Date.split(":") +# if len(Parts) >= 2: +# inFormat = 12 +# # May be YYYY-MM-DD HH:MM... +# elif Date.find("-") != -1: +# Parts = Date.split("-") +# if len(Parts) == 3: +# inFormat = 22 +# # YYYYMMMDD - 68APR3 will pass. +# elif (Date.find("A") != -1 or Date.find("E") != -1 or +# Date.find("O") != -1 or Date.find("U") != -1): +# inFormat = 32 +# # If it is still 0 then something is wrong. +# if inFormat == 0: +# if verify is False: +# return "" +# else: +# return (1, "RW", "Bad date/time(%d): '%s'" % +# (inFormat, dateTime), 2, "") +# # These can be fed from the Format 0 stuff above, or called directly +# # if the caller knows what dateTime is. +# if inFormat < 20: +# # YYYY:DOY:HH:MM:SS.sss +# # Sometimes this comes as YYYY:DOY:HH:MM:SS:sss. We'll look for +# # that here. (It's a Reftek thing.) +# if inFormat == 11: +# DT = dateTime.split(":") +# DT += (5 - len(DT)) * ["0"] +# if len(DT) == 6: +# DT[4] = "%06.3f" % (intt(DT[4]) + intt(DT[5]) / 1000.0) +# DT = DT[:-1] +# # YYYY:DOY HH:MM:SS.sss +# elif inFormat == 12: +# Parts = dateTime.split() +# Date = Parts[0].split(":") +# Date += (2 - len(Date)) * ["0"] +# Time = Parts[1].split(":") +# Time += (3 - len(Time)) * ["0"] +# DT = Date + Time +# else: +# if verify is False: +# return "" +# else: +# return (1, "MWX", "dt2Time: Unknown inFormat code (%d)." % +# inFormat, 3, "") +# # Two-digit years shouldn't happen a lot, so this is kinda +# # inefficient. +# if DT[0] < "100": +# YYYY = intt(Date[0]) +# if YYYY < 70: +# YYYY += 2000 +# else: +# YYYY += 1900 +# DT[0] = str(YYYY) +# # After we have all of the parts then do the check if the caller +# # wants. +# if verify is True: +# Ret = dt2Timeverify("ydhms", DT) +# if Ret[0] != 0: +# return Ret +# # I'm using intt() and floatt() throughout just because it's safer +# # than the built-in functions. +# # This trick makes it so the Epoch for a year only has to be +# # calculated once during a program's run. +# YYYY = intt(DT[0]) +# DOY = intt(DT[1]) +# MMM, DD = dt2Timeydoy2md(YYYY, DOY) +# HH = intt(DT[2]) +# MM = intt(DT[3]) +# SS = floatt(DT[4]) +# elif inFormat < 30: +# # YYYY-MM-DD:HH:MM:SS.sss +# if inFormat == 21: +# Parts = dateTime.split(":", 1) +# Date = Parts[0].split("-") +# Date += (3 - len(Date)) * ["0"] +# # Just the date must have been supplied. +# if len(Parts) == 1: +# Time = ["0", "0", "0"] +# else: +# Time = Parts[1].split(":") +# Time += (3 - len(Time)) * ["0"] +# DT = Date + Time +# # YYYY-MM-DD HH:MM:SS.sss +# elif inFormat == 22: +# Parts = dateTime.split() +# Date = Parts[0].split("-") +# Date += (3 - len(Date)) * ["0"] +# Time = Parts[1].split(":") +# Time += (3 - len(Time)) * ["0"] +# DT = Date + Time +# # If parts of 23 are missing we will fill them in with Jan, 1st, +# # or 00:00:00. +# # If parts of 24 are missing we will format to the missing item +# # then stop and return what we have. +# elif inFormat == 23 or inFormat == 24: +# # The /DOY may or may not be there. +# if dateTime.find("/") == -1: +# Parts = dateTime.split() +# Date = Parts[0].split("-") +# if inFormat == 23: +# Date += (3 - len(Date)) * ["1"] +# else: +# # The -1's will stand in from the missing items. +# # outFormat=24 will figure it out from there. +# Date += (3 - len(Date)) * ["-1"] +# if len(Parts) == 2: +# Time = Parts[1].split(":") +# if inFormat == 23: +# Time += (3 - len(Time)) * ["0"] +# else: +# Time += (3 - len(Time)) * ["-1"] +# else: +# if inFormat == 23: +# Time = ["0", "0", "0"] +# else: +# Time = ["-1", "-1", "-1"] +# # Has a /. We'll only use the YYYY-MM-DD part and assume +# # nothing about the DOY part. +# else: +# Parts = dateTime.split() +# Date = Parts[0].split("-") +# if inFormat == 23: +# Date += (3 - len(Date)) * ["0"] +# elif inFormat == 24: +# Date += (3 - len(Date)) * ["-1"] +# Date[2] = Date[2].split("/")[0] +# if len(Parts) == 2: +# Time = Parts[1].split(":") +# if inFormat == 23: +# Time += (3 - len(Time)) * ["0"] +# else: +# Time += (3 - len(Time)) * ["-1"] +# else: +# if inFormat == 23: +# Time = ["0", "0", "0"] +# else: +# Time = ["1-", "-1", "-1"] +# DT = Date + Time +# else: +# if verify is False: +# return "" +# else: +# return (1, "MWX", "dt2Time: Unknown inFormat code (%d)." % +# inFormat, 3, "") +# if DT[0] < "100": +# YYYY = intt(DT[0]) +# if YYYY < 70: +# YYYY += 2000 +# else: +# YYYY += 1900 +# DT[0] = str(YYYY) +# if verify is True: +# if inFormat != 24: +# Ret = dt2Timeverify("ymdhms", DT) +# else: +# Ret = dt2Timeverify("xymdhms", DT) +# if Ret[0] != 0: +# return Ret +# YYYY = intt(DT[0]) +# MMM = intt(DT[1]) +# DD = intt(DT[2]) +# # This will get done in outFormat=24. +# if inFormat != 24: +# DOY = dt2Timeymd2doy(YYYY, MMM, DD) +# else: +# DOY = -1 +# HH = intt(DT[3]) +# MM = intt(DT[4]) +# SS = floatt(DT[5]) +# elif inFormat < 40: +# # YYYYMMMDD:HH:MM:SS.sss +# if inFormat == 31: +# Parts = dateTime.split(":", 1) +# Date = Parts[0] +# if len(Parts) == 1: +# Time = ["0", "0", "0"] +# else: +# Time = Parts[1].split(":") +# Time += (3 - len(Time)) * ["0"] +# # YYYYMMMDD HH:MM:SS.sss +# elif inFormat == 32: +# Parts = dateTime.split() +# Date = Parts[0] +# Time = Parts[1].split(":") +# Time += (3 - len(Time)) * ["0"] +# else: +# if verify is False: +# return "" +# else: +# return (1, "MWX", "dt2Time: Unknown inFormat code (%d)." % +# inFormat, 3, "") +# # Date is still "YYYYMMMDD", so just make place holders. +# DT = ["0", "0", "0"] + Time +# YYYY = intt(Date) +# if YYYY < 100: +# if YYYY < 70: +# YYYY += 2000 +# else: +# YYYY += 1900 +# MMM = 0 +# DD = 0 +# M = 1 +# for Month in PROG_CALMONS[1:]: +# try: +# i = Date.index(Month) +# MMM = M +# DD = intt(Date[i + 3:]) +# break +# except Exception: +# pass +# M += 1 +# if verify is True: +# # DT values need to be strings for the dt2Timeverify() intt() +# # call. It's assumed the values would come from split()'ing +# # something, so they would normally be strings to begin with. +# DT[0] = str(YYYY) +# DT[1] = str(MMM) +# DT[2] = str(DD) +# Ret = dt2Timeverify("ymdhms", DT) +# if Ret[0] != 0: +# return Ret +# DOY = dt2Timeymd2doy(YYYY, MMM, DD) +# HH = intt(Time[0]) +# MM = intt(Time[1]) +# SS = intt(Time[2]) +# elif inFormat < 50: +# # YYYYDOYHHMMSS +# if inFormat == 41: +# if dateTime.isdigit() is False: +# if verify is False: +# return "" +# else: +# return (1, "RW", "Non-digits in value.", 2) +# YYYY = intt(dateTime[:4]) +# DOY = intt(dateTime[4:7]) +# HH = intt(dateTime[7:9]) +# MM = intt(dateTime[9:11]) +# SS = floatt(dateTime[11:]) +# if verify is True: +# DT = [] +# DT.append(str(YYYY)) +# DT.append(str(DOY)) +# DT.append(str(HH)) +# DT.append(str(MM)) +# DT.append(str(SS)) +# Ret = dt2Timeverify("ydhms", DT) +# if Ret[0] != 0: +# return Ret +# MMM, DD = dt2Timeydoy2md(YYYY, DOY) +# else: +# if verify is False: +# return "" +# else: +# return (1, "MWX", "dt2Time: Unknown inFormat code (%d)." % +# inFormat, 3, "") +# elif inFormat < 60: +# # YYYYMMDDHHMMSS +# if inFormat == 51: +# if dateTime.isdigit() is False: +# if verify is False: +# return "" +# else: +# return (1, "RW", "Non-digits in value.", 2) +# YYYY = intt(dateTime[:4]) +# MMM = intt(dateTime[4:6]) +# DD = intt(dateTime[6:8]) +# HH = intt(dateTime[8:10]) +# MM = intt(dateTime[10:12]) +# SS = floatt(dateTime[12:]) +# if verify is True: +# DT = [] +# DT.append(str(YYYY)) +# DT.append(str(MMM)) +# DT.append(str(DD)) +# DT.append(str(HH)) +# DT.append(str(MM)) +# DT.append(str(SS)) +# Ret = dt2Timeverify("ymdhms", DT) +# if Ret[0] != 0: +# return Ret +# DOY = dt2Timeymd2doy(YYYY, MMM, DD) +# else: +# if verify is False: +# return "" +# else: +# return (1, "MWX", "dt2Time: Unknown inFormat code (%d)." % +# inFormat, 3, "") +# # If the caller just wants to work with the seconds we'll split it up +# # and return the number of seconds into the day. In this case the +# # outFormat value will not be used. +# elif inFormat == 100: +# Parts = dateTime.split(":") +# Parts += (3 - len(Parts)) * ["0"] +# if verify is True: +# Ret = dt2Timeverify("hms", Parts) +# if Ret[0] != 0: +# return Ret +# if verify is False: +# return (intt(Parts[0]) * 3600) + \ +# (intt(Parts[1]) * 60) + float(Parts[2]) +# else: +# return (0, (intt(Parts[0]) * 3600) + (intt(Parts[1]) * 60) + +# float(Parts[2])) +# # Now that we have all of the parts do what the caller wants and return the +# # result. +# # Return the Epoch. +# if outFormat == -1: +# try: +# Epoch = Y2EPOCH[YYYY] +# except KeyError: +# Epoch = 0.0 +# for YYY in range(1970, YYYY): +# if YYY % 4 != 0: +# Epoch += 31536000.0 +# elif YYY % 100 != 0 or YYY % 400 == 0: +# Epoch += 31622400.0 +# else: +# Epoch += 31536000.0 +# Y2EPOCH[YYYY] = Epoch +# Epoch += ((DOY - 1) * 86400.0) + (HH * 3600.0) + (MM * 60.0) + SS +# if verify is False: +# return Epoch +# else: +# return (0, Epoch) +# elif outFormat == 0: +# if verify is False: +# return YYYY, MMM, DD, DOY, HH, MM, SS +# else: +# return (0, YYYY, MMM, DD, DOY, HH, MM, SS) +# elif outFormat == 1: +# Format = dateFormat +# if Format == "YYYY:DOY": +# outFormat = 11 +# elif Format == "YYYY-MM-DD": +# outFormat = 22 +# elif Format == "YYYYMMMDD": +# outFormat = 32 +# # Usually used for troubleshooting. +# elif len(Format) == 0: +# try: +# Epoch = Y2EPOCH[YYYY] +# except KeyError: +# for YYY in range(1970, YYYY): +# if YYY % 4 != 0: +# Epoch += 31536000.0 +# elif YYY % 100 != 0 or YYY % 400 == 0: +# Epoch += 31622400.0 +# else: +# Epoch += 31536000.0 +# Y2EPOCH[YYYY] = Epoch +# Epoch += ((DOY - 1) * 86400.0) + (HH * 3600.0) + (MM * 60.0) + SS +# if verify is False: +# return Epoch +# else: +# return (0, Epoch) +# # This is the easiest way I can think of to keep an SS of 59.9999 from +# # being rounded and formatted to 60.000. Some stuff at some point may slip +# # into the microsecond realm. Then this whole library of functions may have +# # to be changed. +# if SS % 1 > .999: +# SS = int(SS) + .999 +# # These outFormat values are the same as inFormat values, plus others. +# # YYYY:DOY:HH:MM:SS.sss +# if outFormat == 11: +# if verify is False: +# return "%d:%03d:%02d:%02d:%06.3f" % (YYYY, DOY, HH, MM, SS) +# else: +# return (0, "%d:%03d:%02d:%02d:%06.3f" % (YYYY, DOY, HH, MM, SS)) +# # YYYY:DOY HH:MM:SS.sss +# elif outFormat == 12: +# if verify is False: +# return "%d:%03d %02d:%02d:%06.3f" % (YYYY, DOY, HH, MM, SS) +# else: +# return (0, "%d:%03d %02d:%02d:%06.3f" % (YYYY, DOY, HH, MM, SS)) +# # YYYY:DOY - just because it's popular (for LOGPEEK) and it saves having +# # the caller always doing .split()[0] +# elif outFormat == 13: +# if verify is False: +# return "%d:%03d" % (YYYY, DOY) +# else: +# return (0, "%d:%03d" % (YYYY, DOY)) +# # YYYY:DOY:HH:MM:SS - just because it's really popular in POCUS and other +# # programs. +# elif outFormat == 14: +# if verify is False: +# return "%d:%03d:%02d:%02d:%02d" % (YYYY, DOY, HH, MM, int(SS)) +# else: +# return (0, "%d:%03d:%02d:%02d:%02d" % (YYYY, DOY, HH, MM, int(SS))) +# # YYYY-MM-DD:HH:MM:SS.sss +# elif outFormat == 21: +# if verify is False: +# return "%d-%02d-%02d:%02d:%02d:%06.3f" % (YYYY, MMM, DD, HH, MM, +# SS) +# else: +# return (0, "%d-%02d-%02d:%02d:%02d:%06.3f" % (YYYY, MMM, DD, HH, +# MM, SS)) +# # YYYY-MM-DD HH:MM:SS.sss +# elif outFormat == 22: +# if verify is False: +# return "%d-%02d-%02d %02d:%02d:%06.3f" % (YYYY, MMM, DD, HH, MM, +# SS) +# else: +# return (0, "%d-%02d-%02d %02d:%02d:%06.3f" % (YYYY, MMM, DD, HH, +# MM, SS)) +# # YYYY-MM-DD/DOY HH:MM:SS.sss +# elif outFormat == 23: +# if verify is False: +# return "%d-%02d-%02d/%03d %02d:%02d:%06.3f" % (YYYY, MMM, DD, DOY, +# HH, MM, SS) +# else: +# return (0, "%d-%02d-%02d/%03d %02d:%02d:%06.3f" % (YYYY, MMM, DD, +# DOY, HH, MM, +# SS)) +# # Some portion of YYYY-MM-DD HH:MM:SS. Returns integer seconds. +# # In that this is a human-entered thing (programs don't store partial +# # date/times) we'll return whatever was entered without the /DOY, since the +# # next step would be to do something like look it up in a database. +# elif outFormat == 24: +# dateTime = "%d" % YYYY +# if MMM != -1: +# dateTime += "-%02d" % MMM +# else: +# # Return what we have if this item was not provided, same on down. +# if verify is False: +# return dateTime +# else: +# return (0, dateTime) +# if DD != -1: +# dateTime += "-%02d" % DD +# else: +# if verify is False: +# return dateTime +# else: +# return (0, dateTime) +# if HH != -1: +# dateTime += " %02d" % HH +# else: +# if verify is False: +# return dateTime +# else: +# return (0, dateTime) +# if MM != "-1": +# dateTime += ":%02d" % MM +# else: +# if verify is False: +# return dateTime +# else: +# return (0, dateTime) +# # Returns integer second since the caller has no idea what is coming +# # back. +# if SS != "-1": +# dateTime += ":%02d" % SS +# if verify is False: +# return dateTime +# else: +# return (0, dateTime) +# # YYYY-MM-DD +# elif outFormat == 25: +# if verify is False: +# return "%d-%02d-%02d" % (YYYY, MMM, DD) +# else: +# return (0, "%d-%02d-%02d" % (YYYY, MMM, DD)) +# # YYYYMMMDD:HH:MM:SS.sss +# elif outFormat == 31: +# if verify is False: +# return "%d%s%02d:%02d:%02d:%06.3f" % (YYYY, PROG_CALMONS[MMM], DD, +# HH, MM, SS) +# else: +# return (0, "%d%s%02d:%02d:%02d:%06.3f" % (YYYY, PROG_CALMONS[MMM], +# DD, HH, MM, SS)) +# # YYYYMMMDD HH:MM:SS.sss +# elif outFormat == 32: +# if verify is False: +# return "%d%s%02d %02d:%02d:%06.3f" % (YYYY, PROG_CALMONS[MMM], DD, +# HH, MM, SS) +# else: +# return (0, "%d%s%02d %02d:%02d:%06.3f" % (YYYY, PROG_CALMONS[MMM], +# DD, HH, MM, SS)) +# # YYYYDOYHHMMSS.sss +# elif outFormat == 41: +# if verify is False: +# return "%d%03d%02d%02d%06.3f" % (YYYY, DOY, HH, MM, SS) +# else: +# return (0, "%d%03d%02d%02d%06.3f" % (YYYY, DOY, HH, MM, SS)) +# # YYYYMMDDHHMMSS.sss +# elif outFormat == 51: +# if verify is False: +# return "%d%02d%02d%02d%02d%06.3f" % (YYYY, MMM, DD, HH, MM, SS) +# else: +# return (0, "%d%02d%02d%02d%02d%06.3f" % (YYYY, MMM, DD, HH, MM, +# SS)) +# # Returns what ever OPTdateFormatRVar is set to. +# # 80 is dt, 81 is d and 82 is t. +# elif outFormat == 80 or outFormat == 81 or outFormat == 82: +# if dateFormat == "YYYY:DOY": +# if outFormat == 80: +# if verify is False: +# return "%d:%03d:%02d:%02d:%06.3f" % (YYYY, DOY, HH, MM, SS) +# else: +# return (0, "%d:%03d:%02d:%02d:%06.3f" % (YYYY, DOY, HH, MM, +# SS)) +# elif outFormat == 81: +# if verify is False: +# return "%d:%03d" % (YYYY, DOY) +# else: +# return (0, "%d:%03d" % (YYYY, DOY)) +# elif outFormat == 82: +# if verify is False: +# return "%02d:%02d:%06.3f" % (HH, MM, SS) +# else: +# return (0, "%02d:%02d:%06.3f" % (HH, MM, SS)) +# elif dateFormat == "YYYY-MM-DD": +# if outFormat == 80: +# if verify is False: +# return "%d-%02d-%02d %02d:%02d:%06.3f" % (YYYY, MMM, DD, +# HH, MM, SS) +# else: +# return (0, "%d-%02d-%02d %02d:%02d:%06.3f" % (YYYY, MMM, +# DD, HH, MM, +# SS)) +# elif outFormat == 81: +# if verify is False: +# return "%d-%02d-%02d" % (YYYY, MMM, DD) +# else: +# return (0, "%d-%02d-%02d" % (YYYY, MMM, DD)) +# elif outFormat == 82: +# if verify is False: +# return "%02d:%02d:%06.3f" % (HH, MM, SS) +# else: +# return (0, "%02d:%02d:%06.3f" % (HH, MM, SS)) +# elif dateFormat == "YYYYMMMDD": +# if outFormat == 80: +# if verify is False: +# return "%d%s%02d %02d:%02d:%06.3f" % (YYYY, +# PROG_CALMONS[MMM], +# DD, HH, MM, SS) +# else: +# return (0, "%d%s%02d %02d:%02d:%06.3f" % +# (YYYY, PROG_CALMONS[MMM], DD, HH, MM, SS)) +# elif outFormat == 81: +# if verify is False: +# return "%d%s%02d" % (YYYY, PROG_CALMONS[MMM], DD) +# else: +# return (0, "%d%s%02d" % (YYYY, PROG_CALMONS[MMM], DD)) +# elif outFormat == 82: +# if verify is False: +# return "%02d:%02d:%06.3f" % (HH, MM, SS) +# else: +# return (0, "%02d:%02d:%06.3f" % (HH, MM, SS)) +# elif len(dateFormat) == 0: +# if verify is False: +# return str(dateTime) +# else: +# return (0, str(dateTime)) +# else: +# if verify is False: +# return "" +# else: +# return (1, "MWX", "dt2Time: Unknown outFormat code (%d)." % +# outFormat, 3, "") +# +# ################################ +# # BEGIN: dt2Timedhms2Secs(InStr) +# # FUNC:dt2Timedhms2Secs():2018.235 +# # Returns the number of seconds in strings like 1h30m. +# +# +# def dt2Timedhms2Secs(InStr): +# InStr = InStr.replace(" ", "").lower() +# if len(InStr) == 0: +# return 0 +# Chars = list(InStr) +# Value = 0 +# SubValue = "" +# for Char in Chars: +# if Char.isdigit(): +# SubValue += Char +# elif Char == "s": +# Value += intt(SubValue) +# SubValue = "" +# elif Char == "m": +# Value += intt(SubValue) * 60 +# SubValue = "" +# elif Char == "h": +# Value += intt(SubValue) * 3600 +# SubValue = "" +# elif Char == "d": +# Value += intt(SubValue) * 86400 +# SubValue = "" +# # Must have just been passed a number with no s m h or d or 1h30 which will +# # be treated as 1 hour, 30 seconds. +# if len(SubValue) != 0: +# Value += intt(SubValue) +# return Value diff --git a/sohstationviewer/controller/core/utils_tmp.py b/sohstationviewer/controller/core/utils_tmp.py new file mode 100644 index 0000000000000000000000000000000000000000..510bb05b69e87c7082b3f21716a5d445eac118b1 --- /dev/null +++ b/sohstationviewer/controller/core/utils_tmp.py @@ -0,0 +1,77 @@ +################# +# BEGIN: intt(In) +# LIB:intt():2018.257 +# Handles all of the annoying shortfalls of the int() function (vs C). +def intt(In): + In = str(In).strip() + if len(In) == 0: + return 0 + # Let the system try it first. + try: + return int(In) + except ValueError: + Number = "" + for c in In: + if c.isdigit(): + Number += c + elif (c == "-" or c == "+") and len(Number) == 0: + Number += c + elif c == ",": + continue + else: + break + try: + return int(Number) + except ValueError: + return 0 +# END: intt + +################### +# BEGIN: floatt(In) +# LIB:floatt():2018.256 +# Handles all of the annoying shortfalls of the float() function (vs C). +# Does not handle scientific notation numbers. +def floatt(In): + In = str(In).strip() + if len(In) == 0: + return 0.0 + # At least let the system give it the ol' college try. + try: + return float(In) + except Exception: + Number = "" + for c in In: + if c.isdigit() or c == ".": + Number += c + elif (c == "-" or c == "+") and len(Number) == 0: + Number += c + elif c == ",": + continue + else: + break + try: + return float(Number) + except ValueError: + return 0.0 +# END: floatt + +###################################### +# BEGIN: rtnPattern(In, Upper = False) +# this may need to be moved to another place +# LIB:rtnPattern():2006.114 +def rtnPattern(In, Upper=False): + Rtn = "" + for c in In: + if c.isdigit(): + Rtn += "0" + elif c.isupper(): + Rtn += "A" + elif c.islower(): + Rtn += "a" + else: + Rtn += c + # So the A/a chars will always be A, so the caller knows what to look for. + if Upper is True: + return Rtn.upper() + return Rtn +# END: rtnPattern \ No newline at end of file diff --git a/sohstationviewer/controller/processing.py b/sohstationviewer/controller/processing.py new file mode 100755 index 0000000000000000000000000000000000000000..14281dbd7807c78f3a24c491c124dd0208480756 --- /dev/null +++ b/sohstationviewer/controller/processing.py @@ -0,0 +1,22 @@ +from sohstationviewer.model.mseed_text import MSeed_Text + + +def loadData(parent, listOfDir, reqInfoChans): + """ + Go through root dir and read all files in that dir and its subdirs + """ + dataObject = None + for d in listOfDir: + if dataObject is None: + # dataObject = Reftek.Reftek(parent, d) + # if dataObject.hasData(): + # continue + dataObject = MSeed_Text(parent, d, reqInfoChans) + if dataObject.hasData(): + continue + # If no data can be read from the first dir, throw exception + raise Exception("No data can be read from ", d) + else: + dataObject.readDir(d) + + return dataObject.plottingData diff --git a/sohstationviewer/model/core/dataType.py b/sohstationviewer/model/core/dataType.py new file mode 100755 index 0000000000000000000000000000000000000000..a7be3da3fef32e50679049ecbf9f6039db05fa00 --- /dev/null +++ b/sohstationviewer/model/core/dataType.py @@ -0,0 +1,64 @@ +import os + + +class WrongDataTypeError(Exception): + def __init__(self, *args, **kwargs): + self.args = (args, kwargs) + + +class DataType: + def __init__(self, parent, dir, reqInfoChans=[]): + self.parent = parent + self.dir = dir + self.reqInfoChans = reqInfoChans + self.noneReqChans = set() + self.curNetStatLoc = ('_', '_', '_') + self.processingLog = [] # [(message, type)] + self.logData = {} + self.plottingData = {} + self.streams = {} + + self.readDir(dir) + + def readFile(self, pathToFile): + pass + + def combineData(self): + """ + Merge channels in each stream + """ + pass + + def readDir(self, dir): + count = 0 + for path, subdirs, files in os.walk(dir): + + for fileName in files: + if fileName.startswith('._'): + # skip mac's info file + continue + if not os.path.isfile(os.path.join(path, fileName)): + continue + self.readFile(path, fileName) + count += 1 + if count % 50 == 0: + self.displayTrackingInfo("Reading file %s" % count, + 'info') + self.combineData() + + def hasData(self): + if len(self.logData) == 0 and len(self.plottingData) == 0: + return False + return True + + def displayTrackingInfo(self, text, type): + """ + :param text: text to be displayed + :param type: info/warning/error + """ + print("displayTrackingInfo:", text) + self.parent.displayTrackingInfo(text, type) + + def trackInfo(self, text, type): + self.displayTrackingInfo(text, type) + self.processingLog.append((text, type)) diff --git a/sohstationviewer/model/mseed_text.py b/sohstationviewer/model/mseed_text.py new file mode 100755 index 0000000000000000000000000000000000000000..7218004d9ef1bccbc8cca68faaf3e5d8d456b248 --- /dev/null +++ b/sohstationviewer/model/mseed_text.py @@ -0,0 +1,203 @@ +import os + +from obspy.core import Stream, read as read_ms +from obspy import UTCDateTime +from struct import unpack + +from sohstationviewer.model.core.dataType import DataType + + +class MSeed_Text(DataType): + def __init__(self, *kwarg): + self.readBlkt = {500: self.readBlkt500} + super().__init__(*kwarg) + + def readFile(self, path, fileName): + if not self.readMiniseed(path, fileName): + self.readText(path, fileName) + + def combineData(self): + for k in self.streams: # k=netID, statID, locID + stream = self.streams[k] + stream.merge() + # gaps is list of [network, station, location, channel, starttime, + # endtime, duration, number of missing samples] + gaps = stream.get_gaps() + # stream.print_gaps() + gaps = self.squashGaps(gaps) + self.plottingData[k] = {'gaps': gaps, + 'channels': {}} + maxEndtime = UTCDateTime(0) + minStarttime = UTCDateTime(20E10) + for trace in stream: + startTm, endTm = self.readTrace( + trace, self.plottingData[k]['channels']) + if startTm < minStarttime: + minStarttime = startTm + if endTm > maxEndtime: + maxEndtime = endTm + self.plottingData[k]['earliestUTC'] = minStarttime + self.plottingData[k]['latestUTC'] = maxEndtime + + def addLog(self, chan, logText): + if chan not in self.logData[self.curNetStatLoc].keys(): + self.logData[self.curNetStatLoc][chan] = [] + self.logData[self.curNetStatLoc][chan].append(logText) + + def readText(self, path, fileName): + """ + Read log file and add to logData under channel TEXT + """ + with open(os.path.join(path, fileName), 'r') as file: + try: + content = file.read() + except UnicodeDecodeError: + self.trackInfo("Can't process file: %s" % fileName, 'error') + return + logText = "\n\n** STATE OF HEALTH: %s\n" % fileName + logText += content + self.addLog('TEXT', logText) + + def readMiniseed(self, path, fileName): + """ + Read ms and add trace in self.streams to merge later + Or read log wrap in ms and add to logData under channel in ms header + """ + try: + stream = read_ms(os.path.join(path, fileName)) + except TypeError: + return False + + file = None + for trace in stream: + chanID = trace.stats['channel'] + if chanID not in self.reqInfoChans: + self.noneReqChans.add(chanID) + continue + netID = trace.stats['network'] + statID = trace.stats['station'] + locID = trace.stats['location'] + self.curNetStatLoc = k = (netID, statID, locID) + if trace.stats.mseed['encoding'] == 'ASCII': + file = self.readASCII(path, fileName, file, trace, k) + else: + if k not in self.streams.keys(): + self.streams[k] = Stream() + self.streams[k].append(trace) + if file is not None: + file.close() + return True + + def readASCII(self, path, fileName, file, trace, k): + byteorder = trace.stats.mseed['byteorder'] + h = trace.stats + logText = "\n\n**** STATE OF HEALTH: " + logText += ("From:%s To:%s\n" % (h.starttime, h.endtime)) + textFromData = trace.data.tobytes().decode() + if textFromData != '': + logText += textFromData + else: + recLen = h.mseed['record_length'] + if file is None: + file = open(os.path.join(path, fileName), 'rb') + databytes = file.read(recLen) + followingBlktNum = unpack('%s%s' % (byteorder, 'B'), + databytes[39:40])[0] + if followingBlktNum > 1: + # skip blockette 1000 + nextBlocketteType = unpack('%s%s' % (byteorder, 'H'), + databytes[56:58])[0] + try: + logText += self.readBlkt[nextBlocketteType](databytes, + byteorder) + except KeyError: + msg = ("Function to read blockette %s isn't implemented " + "yet. Implementer needs to write and add the " + "function to the dict self.readBlkt in Mseed_Text." + "__init__()" % nextBlocketteType) + self.trackInfo(msg, 'error') + return file + if k not in self.logData: + self.logData[k] = {} + if h.channel not in self.logData[k]: + self.logData[k][h.channel] = [] + self.logData[k][h.channel].append(logText) + return file + + def readBlkt500(self, databytes, byteorder): + t = {} + (vcocorr, t['year'], t['doy'], t['hour'], t['min'], t['sec'], + junk, t['micro'], t['micro2'], qual, cnt, type, mod, stat + ) = unpack('%s%s' % (byteorder, 'fHHBBBBHBBI16s32s128s'), + databytes[60:256]) + logText = "\nVCO Correction: %s" % vcocorr + logText += ("\nTime of exception: %(year)s:%(doy)s:%(hour)s:%(min)s:" + "%(sec)s:%(micro)s:%(micro2)s" % t) + logText += "\nReception Quality: %s" % qual + logText += "\nException Count: %s" % cnt + logText += "\nException Type: %s" % type.strip() + logText += "\nClock Model: %s" % mod.strip() + logText += "\nClock Status: %s" % stat.strip() + return logText + + def readTrace(self, trace, channels): + chan = {} + chan['netID'] = trace.stats['network'] + chan['statID'] = trace.stats['station'] + chan['locID'] = trace.stats['location'] + chanID = chan['chanID'] = trace.stats['channel'] + chan['samplerate'] = trace.stats['sampling_rate'] + chan['startTmEpoch'] = trace.stats['starttime'].timestamp + chan['endTmEpoch'] = trace.stats['endtime'].timestamp + """ + trace time start with 0 => need to add with epoch starttime + """ + chan['times'] = trace.times() + trace.stats['starttime'].timestamp + chan['data'] = trace.data + if chanID not in channels.keys(): + channels[chanID] = chan + else: + msg = ("Something wrong with code logic." + "After stream is merged there should be only one trace " + "for channel %s: %s" % (chanID, trace)) + self.trackInfo(msg, "error") + return trace.stats['starttime'], trace.stats['endtime'] + + def squashGaps(self, gaps): + """ + Squash different lists of gaps for all channels to be one list of + (minStarttime, maxEndtime) gaps + : param gaps: list of [network, station, location, channel, starttime, + endtime, duration, number of missing samples] + : return squashedGaps + """ + if len(gaps) == 0: + return gaps + + # create dict consist of list of gaps for each channel + gaps_dict = {} + for g in gaps: + if g[3] not in gaps_dict: + gaps_dict[g[3]] = [] + gaps_dict[g[3]].append((g[4].timestamp, g[5].timestamp)) + + firstLen = len(gaps_dict[gaps[0][3]]) + diffLenList = [len(gaps_dict[k]) for k in gaps_dict.keys() + if len(gaps_dict[k]) != firstLen] + if len(diffLenList) > 0: + msg = "Number of Gaps for different channel are not equal.\n" + for k in gaps_dict.keys(): + msg += "%s: %s\n" % (k, len(gaps_dict[k])) + self.displayTrackingInfo(msg, 'error') + return [] + squashedGaps = [] + for i in range(firstLen): + maxEndtime = 0 + minStarttime = 1E100 + for val in gaps_dict.values(): + if val[i][0] < minStarttime: + minStarttime = val[i][0] + if val[i][1] > maxEndtime: + maxEndtime = val[i][1] + squashedGaps.append((minStarttime, maxEndtime)) + return squashedGaps diff --git a/sohstationviewer/view/mainwindow.py b/sohstationviewer/view/mainwindow.py index a1a2fe96fc29bd23415b30cf5595f241a456ab3c..30b7c785670952fdd90c528ad15770ed6b72cd45 100755 --- a/sohstationviewer/view/mainwindow.py +++ b/sohstationviewer/view/mainwindow.py @@ -64,12 +64,12 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): # Connect slots to change the date format displayed # by the QDateEdit widgets - # self.showYYYYDOYDates.triggered.connect(lambda: - # self.setDateFormat('yyyy:D')) - self.showYYYY_MM_DDDates.triggered.connect(lambda: - self.setDateFormat('yyyy-MM-dd')) - self.showYYYYMMMDDDates.triggered.connect(lambda: - self.setDateFormat('yyyyMMMdd')) + # self.showYYYYDOYDates.triggered.connect( + # lambda: self.setDateFormat('yyyy:D')) + self.showYYYY_MM_DDDates.triggered.connect( + lambda: self.setDateFormat('yyyy-MM-dd')) + self.showYYYYMMMDDDates.triggered.connect( + lambda: self.setDateFormat('yyyyMMMdd')) self.timeToDateEdit.setCalendarWidget(CalendarWidget(self)) self.timeToDateEdit.setDate(QtCore.QDate.currentDate()) @@ -80,7 +80,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): # self.showYYYYDOYDates.triggered.emit() self.showYYYY_MM_DDDates.triggered.emit() - self.openFilesList.itemDoubleClicked.connect(self.openFilesListItemDoubleClicked) + self.openFilesList.itemDoubleClicked.connect( + self.openFilesListItemDoubleClicked) pal = self.openFilesList.palette() pal.setColor(QtGui.QPalette.Highlight, QtGui.QColor(128, 255, 128))