#!/usr/bin/env python """ 2012-03-05, weeee! This is a really simple script, the docs are WAY longer, that dices a date-string returning a list of integers or a dict if key-words are supplied. ... IT SLICES, IT DICES, IT HAS SHARP EDGES! =============================================== Not production-ready, 'nless you like to play with razors. There is no type-checking, no assertion for field-order etc. This simply, blindly and unintelligently guts the string. If the order changes, it bites... you get the idea. Some examples, more plus arg-defs b'low TEST_DATE = "2012-03-05 13:05:14.453728" # return list of int's in original order cheap_date(TEST_DATE) [2012, 3, 5, 13, 5, 14, 453728] ISO_KEYS = ['t_year','t_mon','...'t_sec','t_usec'] # return same list, mapped into a dict cheap_date(TEST_DATE, ISO_KEYS) {'t_mon': 3, 't_min': 5, 't_sec': 14, 't_hour': 13, 't_day': 5, 't_year': 2012, 't_usec': 453728} # Keep the decimal t'gether using non-default regex # Note: list is str's, int("12.34") razors a ValueError cheap_date(TEST_DATE, [], DIG_N_DEC, str) ['2012', '03', '05', '13', '05', '14.453728'] # dict's and format strings, naturally sweeeeet FMT_STR % cheap_date(TEST_DATE, ISO_KEYS, DIG_N_DEC, PAT) 2012-03-05T13:05:14.454 FMT_STR2 % cheap_date(TEST_DATE, ISO_KEYS, val_conv = str) 13:05-03/05/2012 """ import re def cheap_date(dt_str, kw_list = [], reg_xp = r'\D', val_conv = int): """ Cheap incremental date parser preserving ISO microseconds dt_str: String representing source date pass "2012-03-05 13:05:14.453728" returns [2012, 3, 5, 13, 5, 14, 453728] optional- ['2012', '03', '05', '13', '05', '14.453728'] returns {'tm_year': 2012, 'tm_mday': 5, 'tm_mon': 3 ... } Optional arguments: kw_list: Ordered list of return-dictionary keys reg_xp: Regular expression used to split the string val_conv: List-processor for data-conversion i.e. str --> int >>> cheap_date(TEST_DATE) [2012, 3, 5, 13, 5, 14, 453728] >>> cheap_date(TEST_DATE, ISO_KEYS[:3]) {'t_mon': 3, 't_day': 5, 't_year': 2012} >>> FMT_STR2 % cheap_date(TEST_DATE, ISO_KEYS, val_conv = str) '13:05-03/05/2012' """ # shake the numbers out with re ['2012', '03'...] tm_list = re.split(reg_xp, dt_str) # juice 'em: apply function to each list-value [2012, 03...] # you _could_ test if val_conv == str an omit this step tm_list = map(val_conv, tm_list) # Existence of this list, enables return of a dictionary if kw_list: # fabricate list of key-value pairs [['yr',2012],[....],] tm_list = zip(kw_list, tm_list) # map the key-val pairs into a dict to be proud of tm_list = dict(tm_list) return tm_list def cheaper_date(dt_str, kw_list = [], reg_xp = r'\D', val_conv = int): """ Cheaper date parser, with a few less teeth >>> FMT_STR2 % cheaper_date(TEST_DATE, ISO_KEYS, val_conv = str) '13:05-03/05/2012' """ # The functionality above, tucked in a thin blankie. try: tm_list = map(val_conv, re.split(reg_xp, dt_str)) except ValueError, e: print "Conversion proc (int?) spewed a matched value" print e raise if kw_list: tm_list = dict(zip(kw_list, tm_list)) return tm_list if __name__ == '__main__': import doctest # Some Q&D convenience, ta get 'r done. TEST_DATE = "2012-03-05 13:05:14.453728" # Keys match number-seq. order of date to parse ISO_KEYS = ['t_year','t_mon','t_day','t_hour','t_min','t_sec','t_usec'] # Slow lrner moi! Ages till I grep'd the non-obv. & betwix da lines. # A.K.A: "To select or not select? TITQ!" I mean "\d" to "\D" # The following exp. splits, and discards, NON-number sequences. DIGITS_ONLY = r'\D' # DEFAULT, digits only: 12.56-> ['12','56'] # \d is inverse|not \D, [^....] inverse|not's the match DIG_N_DEC = r'[^\d\.]' # retain decmal no's 34.78-> ['34.78',] # With a dict[ionary] and format strings, it happens eh? FMT_STR = "T".join(["%(t_year)d-%(t_mon)02d-%(t_day)02d", "%(t_hour)02d:%(t_min)02d:%(t_sec)0.3f"]) # Same info, just shuffled for my simple-minded amusement FMT_STR2 = "%(t_hour)s:%(t_min)s-%(t_mon)s/%(t_day)s/%(t_year)s" # Pick-A-Type... for demo. Its stupid, assumes a string of digits only. # There are safer/elegantisher ways to do this... more calories though. def PAT(s): try: return int(s) except ValueError: return float(s) doctest.testmod()