예제 #1
0
 def isFree(dt):
     '''
     Returns true when the day of the date is either a holiday,
     specialday, non workday or not within the calc cycle.
     '''
     dat = datetime.fromtimestamp(dt).date()
     daystr = datetime.fromtimestamp(dt).strftime("%A").lower()
     datestr = datetime.fromtimestamp(dt).strftime("%d.%m.%Y")
     yearstr = datetime.fromtimestamp(dt).strftime("%Y")
     
     #holidays from settings
     s_holidays=settings.get("holidays")
     
     #Specialdays are free
     s_specialdays=[]
     for specialday in settings.get("specialdays"):
         s_specialdays.append(specialday+"."+yearstr)#Special days in the settings miss the year
     
     #Everything what is not in the calc_cycle is a free day
     if(not settings.get("calc_cycles").get(dat)):#only dates from a user defined range are there
         return True
     
     if(daystr not in settings.get("calc_cycles").get(dat).get("workdays") or (datestr in s_holidays or datestr in s_specialdays)):
         return True
     return False
예제 #2
0
    def _getSingleDay(self, wd):
        '''
        Returns a complete view of the given workday
        '''
        width = settings.get("border_width") - 8
        c1 = floor(width / 10 * 3)
        c2 = floor(width / 10 * 7)

        startStr = datetime.fromtimestamp(wd.start).strftime(
            settings.get("time_format"))
        endStr = datetime.fromtimestamp(
            time.time()).strftime(settings.get("time_format") + " (ongoing)")
        if (wd.end):
            endStr = datetime.fromtimestamp(wd.end).strftime(
                settings.get("time_format"))

        wdstats = Utils.getWDStats(wd)

        info = ""
        if (Utils.isFree(wd.start)):
            info += Utils.pb("THIS IS A FREE DAY")
            info += Utils.pbn()
        info += Utils.pb(
            Utils.pf("Day started", c1) + " > " + Utils.pf(startStr, c2))
        info += Utils.pb(
            Utils.pf("Day ended", c1) + " > " + Utils.pf(endStr, c2))
        info += Utils.pbn()
        if (len(wd.breaks) > 0):
            info += Utils.pb(
                Utils.pf("breaks", c1) + " > " +
                Utils.pf(Utils.formatHM(wdstats.get("breaktime")), c2))
            for bk in wd.breaks:
                bkStart = bk.get("start")
                bkEnd = bk.get("end")
                bkStartStr = datetime.fromtimestamp(bkStart).strftime("%H:%M")
                bkEndStr = datetime.fromtimestamp(
                    time.time()).strftime("%H:%M (ongoing)")
                if (bkEnd):
                    bkEndStr = datetime.fromtimestamp(bkEnd).strftime("%H:%M")
                info += Utils.pb(
                    Utils.pf("", c1) + " ^ " +
                    Utils.pf(bkStartStr + " - " + bkEndStr, c2))
        else:
            info += Utils.pb(
                Utils.pf("Breaks", c1) + " > " + Utils.pf("No breaks", c2))
        info += Utils.pbn()
        info += Utils.pb(
            Utils.pf("Worktime", c1) + " > " +
            Utils.pf(Utils.formatHM(wdstats.get("worktime")), c2))
        return info
예제 #3
0
 def inCalc(ts):
     '''
     Returns true when the day of the date is in the calc cycle.
     '''
     dat=datetime.fromtimestamp(ts).date()
     if settings.get("calc_cycles").get(dat):
         return True
예제 #4
0
 def pfl(text="",size=settings.get("border_width")-5):
     '''
     Fills the given string with - up to the given count
     '''
     if(len(text)<size):
         return text+("-"*(size-len(text)))
     return text
예제 #5
0
 def pfb(text="",size=settings.get("border_width")-5,symbol="#"):
     '''
     Fills the given string with # up to the given count
     '''
     if(len(text)<size):
         return text+(symbol*(size-len(text)))
     return text
예제 #6
0
 def ongoing(self):
     '''
     Print infos about a workday
     '''
     #We want to know the last active workday
     lastwd = Workday.loadLast(settings.get("history_data")).get("workday")
     if (lastwd):
         daystr = datetime.fromtimestamp(lastwd.start).strftime(
             settings.get("date_format"))
         info = Utils.head("Active Workday: " + daystr, symbol="~")
         info += Utils.pbn()
         info += self._getSingleDay(lastwd)
         info += Utils.pbn()
         info += Utils.pbdiv()
         print(info)
         return
     self.l.error("Could not find the last open workday")
예제 #7
0
 def pb(rawstring):
     '''
     Returns text decorated with border
     '''
     out=""
     if rawstring:
         while len(rawstring) > 0:
             out+="| "
             fill=""
             end=len(rawstring)
             if(end > settings.get("border_width")-4):
                 end=settings.get("border_width")-4
             elif(end < settings.get("border_width")-4):
                 fill=" "*((settings.get("border_width")-4)-end)
             out+=rawstring[0:end]+fill+"| \n"
             rawstring=rawstring[end:len(rawstring)+1]
     return out
예제 #8
0
 def head(text, underline=settings.get("border_width")-5,symbol="#"):
     '''
     Returns a head
     '''
     str=""
     str+=Utils.pbn()
     str+=Utils.pb(text)
     str+=Utils.pb(Utils.pfb("",size=underline,symbol=symbol))
     return str
예제 #9
0
 def day(self, ts):
     '''
     Prints the given day
     '''
     wdo = Workday.loadDay(self.historydir, ts)
     wd = wdo.get("workday")
     if (wd):
         daystr = datetime.fromtimestamp(wd.start).strftime(
             settings.get("date_format"))
         info = Utils.head("Day: " + daystr, symbol="~")
         info += Utils.pbn()
         info += self._getSingleDay(wd)
         info += Utils.pbn()
         info += Utils.pbdiv()
         print(info)
         return
     self.l.error(
         "Could not find the specified day: " +
         datetime.fromtimestamp(ts).strftime(settings.get("date_format")))
예제 #10
0
 def getPreviousLastYearDay(ts):
     '''
     Returns the last day of the previous "year" as a timestamp
     The start of the year is defined by year_swap, so this is one day
     before year_swap
     '''
     datnow=datetime.fromtimestamp(ts).date()
     swap=settings.get("year_swap").split(".")
     yearstart=datetime.strptime(swap[0]+"."+swap[1]+"."+str(datnow.year), "%d.%m.%Y").timestamp()
     return yearstart-86400
예제 #11
0
    def rangesToArray():
        '''
        updates the settings by converting all range type like dates into an array
        of dates
        '''

        #Holidays
        arrHolidays = []
        for holiday in settings.get("holidays"):
            rng = holiday.split("-")
            if (len(rng) > 1):
                sDate = datetime.strptime(rng[0], "%d.%m.%Y").date()
                eDate = datetime.strptime(rng[1], "%d.%m.%Y").date()
                dates = Utils.getDatesFromRange(sDate, eDate)
                for rngDate in dates:
                    dt = datetime.fromtimestamp(
                        rngDate.get("timestamp")).strftime("%d.%m.%Y")
                    arrHolidays.append(dt)
            else:
                arrHolidays.append(holiday)
        settings.update({"holidays": arrHolidays})

        tarrClc = {}
        for cycle in settings.get("calc_cycles"):
            for workrange in cycle.get("range"):
                range = workrange.split("-")
                sDate = datetime.strptime(range[0], "%d.%m.%Y").date()
                eDate = datetime.strptime(range[1], "%d.%m.%Y").date()
                for dto in Utils.getDatesFromRange(sDate, eDate):
                    dayname = datetime.fromtimestamp(
                        dto.get("timestamp")).strftime("%A").lower()
                    tarrClc.update({
                        datetime.fromtimestamp(dto.get("timestamp")).date(): {
                            "minutes_per_day": cycle.get("minutes_per_day"),
                            "day": dayname,
                            "workdays": cycle.get("workdays")
                        }
                    })
        settings.update({"calc_cycles": tarrClc})
예제 #12
0
    def getYearDates(ts):
        '''
        Returns an array with all dates within the year of the given timestamp
        based on the year_swap setting
        like:
        [
            {"date": <Date>, "timestamp":<utc_seconds>}...
        ]
        '''
        yeardates=[]
        dateobj=datetime.fromtimestamp(ts).date()
        swap=datetime.strptime(settings.get("year_swap")+"."+str(dateobj.year),"%d.%m.%Y").timestamp()-86400
        if(ts<swap):
            ts=swap=datetime.strptime(settings.get("year_swap")+"."+str(dateobj.year-1),"%d.%m.%Y").timestamp()-8640
            dateobj=datetime.fromtimestamp(ts).date()
        dStart=datetime.strptime(settings.get("year_swap")+"."+str(dateobj.year),"%d.%m.%Y").date()
        lDayTs=datetime.strptime(settings.get("year_swap")+"."+str(dateobj.year),"%d.%m.%Y").timestamp()-86400
        lDayDt=datetime.fromtimestamp(lDayTs).date()
        dEnd=datetime.strptime(str(lDayDt.day)+"."+str(lDayDt.month)+"."+str(dateobj.year+1),"%d.%m.%Y").date()
        
        0

        return Utils.getDatesFromRange(dStart,dEnd)
예제 #13
0
 def last(self):
     '''
     Prints the last closed day
     '''
     #dateObjNow=datetime.fromtimestamp(time.time()).date()
     wd = Workday.loadLastNDay(self.historydir, time.time())
     if (wd):
         daystr = datetime.fromtimestamp(wd.start).strftime(
             settings.get("date_format"))
         info = Utils.head("Day: " + daystr, symbol="~")
         info += Utils.pbn()
         info += self._getSingleDay(wd)
         info += Utils.pbn()
         info += Utils.pbdiv()
         print(info)
         return
     self.l.error("Could not find the last closed workday")
예제 #14
0
    def persist(self, historydir, askoverride=False):
        '''
        persists this workday object
        '''
        
        #(Re)Create history directory in case it got deleted
        if(not os.path.isdir(historydir)):
            os.makedirs(historydir, mode=0o750)

        #Ensure the destination path
        dstfile = self._getWDF(historydir)
        dstdir = os.path.dirname(dstfile)
        if(not os.path.isdir(dstdir)):
            os.makedirs(dstdir, mode=0o750)
        
        if(os.path.isfile(dstfile) and askoverride):
            self.l.error("The file for this workday ("+datetime.fromtimestamp(self.start).strftime(settings.get("date_simple_format"))+") already exists")
            uip = input("Override? [N/y] :")
            if(uip.lower() != "y"):
                exit(0)
                
        #Serialize as json
        with open(dstfile,"w") as f:
            json.dump(self,f,cls=WorkdayJSONEncoder,indent=4)
        
        self.l.info("Persisted "+dstfile)
예제 #15
0
    def saldo(self):
        '''
        Print salo todo/done and time account
        '''
        now = time.time()
        nowd = datetime.fromtimestamp(now)
        reqw = Utils.getRequiredWork(now)
        donew = Utils.getDoneWork(self.historydir, now)
        lastwd = Workday.loadLast(settings.get("history_data")).get("workday")
        width = settings.get("border_width") - 11
        c1w = int(width / 10 * 4)
        c2w = int(width / 10 * 3)
        c3w = int(width / 10 * 3)

        rhYear = Utils.formatHM(reqw.get("year"))
        rhMonth = Utils.formatHM(reqw.get("month"))
        rhWeek = Utils.formatHM(reqw.get("week"))
        rhDay = Utils.formatHM(reqw.get("day"))

        dhYear = Utils.formatHM(donew.get("year"))
        dhMonth = Utils.formatHM(donew.get("month"))
        dhWeek = Utils.formatHM(donew.get("week"))
        dhDay = Utils.formatHM(donew.get("day"))

        thAcc = Utils.formatHM(-reqw.get("now") + donew.get("now"))
        switchDate = settings.get("year_swap")

        info = info = Utils.head("Saldo")
        info += Utils.pbn()
        info += Utils.pb(
            Utils.pf("Entity", c1w) + " | " + Utils.pf("Required ", c2w) +
            " | " + Utils.pf("Worked ", c3w))
        info += Utils.pb("-" * (settings.get("border_width") - 5))
        info += Utils.pb(
            Utils.pf("Year (until " + switchDate + ")", c1w) + " | " +
            Utils.pf(rhYear, c2w) + " | " + Utils.pf(dhYear, c3w))
        info += Utils.pb(
            Utils.pf("Month", c1w) + " | " + Utils.pf(rhMonth, c2w) + " | " +
            Utils.pf(dhMonth, c3w))
        info += Utils.pb(
            Utils.pf("Week", c1w) + " | " + Utils.pf(rhWeek, c2w) + " | " +
            Utils.pf(dhWeek, c3w))
        if (lastwd and not lastwd.end
                and datetime.fromtimestamp(lastwd.start).date() !=
                datetime.fromtimestamp(time.time()).date()):
            datestr = datetime.fromtimestamp(
                lastwd.start).date().strftime("Today (%d.%m - Now)")
            dhLDay = str(floor(donew.get("day") / 3600)) + "h " + str(
                floor(Utils.getWDStats(lastwd).get("worktime") % 3600 /
                      60)) + "m"
            info += Utils.pb(
                Utils.pf(datestr, c1w) + " | " + Utils.pf(rhDay, c2w) + " | " +
                Utils.pf(dhLDay, c3w))
        else:
            info += Utils.pb(
                Utils.pf("Today", c1w) + " | " + Utils.pf(rhDay, c2w) + " | " +
                Utils.pf(dhDay, c3w))
        info += Utils.pb("-" * (settings.get("border_width") - 5))
        info += Utils.pbn()
        info += Utils.pb("Time account (right now): " + thAcc)
        info += Utils.pbn()
        info += Utils.pbdiv()
        print(info)
예제 #16
0
 def getMinutesPerDay(ts):
     '''
     Returns the required worktime in minutes for the date at the given timestamp
     '''
     return settings.get("calc_cycles").get(datetime.fromtimestamp(ts).date()).get("minutes_per_day")*60
예제 #17
0
 def pbn():
     '''
     Returns a newline with decorated border
     '''
     return "|"+(" "*(settings.get("border_width")-3))+"|\n"
예제 #18
0
 def pbdiv():
     '''
     Returns a dividing line
     '''
     return "|"+("-"*(settings.get("border_width")-3))+"|\n"
예제 #19
0
    def _getTbl(self, loadedWDs, saldoBefore=0):
        '''
        Returns a table view of the given loaded workdays
        '''
        info = ""
        width = settings.get("border_width") - 14
        c1 = int(width / 10 * 2.5)
        c2 = int(width / 10 * 2)
        c3 = int(width / 10 * 1.25)
        c4 = int(width / 10 * 1.25)
        c5 = int(width / 10 * 3)
        sbstr = Utils.pf("Saldo", 10) + " (" + Utils.formatHM(
            saldoBefore, posSign=True) + ")"
        info += Utils.pb(
            Utils.pf("Day", c1) + " | " + Utils.pf("Range", c2) + " | " +
            Utils.pf("Required", c3) + " | " + Utils.pf("Worked", c4) + " | " +
            Utils.pf(sbstr, c5))
        ssSaldo = saldoBefore
        for wdIM in loadedWDs:
            t_wd = wdIM.get("workday")
            t_ts = wdIM.get("timestamp")
            t_date = wdIM.get("date")
            t_dt = datetime.fromtimestamp(t_ts).strftime(
                settings.get("date_format"))
            if (t_date == datetime.fromtimestamp(time.time()).date()):
                t_dt = ">> " + t_dt
            if (t_wd and not Utils.isFree(t_ts)):
                reqd = settings.get("calc_cycles").get(
                    wdIM.get("date")).get("minutes_per_day") * 60
                reqdstr = Utils.formatHM(reqd)
                info += Utils.pb(Utils.pfl())
                wdstats = Utils.getWDStats(t_wd)
                worktime = Utils.formatHM(wdstats.get("worktime"))
                reqDiff = wdstats.get("worktime") - reqd
                ssSaldo += reqDiff
                fSaldoStr = Utils.pf(Utils.formatHM(ssSaldo),
                                     10) + " (" + Utils.formatHM(
                                         reqDiff, posSign=True) + ")"
                w_wds = t_wd.start
                w_wde = t_wd.end
                if (not w_wde):  #currently open day
                    w_wde = time.time()
                wdStart = datetime.fromtimestamp(w_wds).strftime("%H:%M")
                wdEnd = datetime.fromtimestamp(w_wde).strftime("%H:%M")
                info += Utils.pb(
                    Utils.pf(t_dt, c1) + " | " +
                    Utils.pf(wdStart + " - " + wdEnd, c2) + " | " +
                    Utils.pf(reqdstr, c3) + " | " + Utils.pf(worktime, c4) +
                    " | " + Utils.pf(fSaldoStr, c5))
            elif (Utils.isFree(t_ts)):  #No need to print free days
                pass
            else:
                reqd = settings.get("calc_cycles").get(
                    wdIM.get("date")).get("minutes_per_day") * 60
                reqdstr = Utils.formatHM(reqd)

                fSaldoStr = ""
                worktimeStr = ""
                if (time.time() > t_ts):
                    ssSaldo -= reqd
                    fSaldoStr = Utils.pf(Utils.formatHM(ssSaldo),
                                         10) + " (" + Utils.formatHM(
                                             -reqd, posSign=True) + ")"

                info += Utils.pb(Utils.pfl())
                info += Utils.pb(
                    Utils.pf(t_dt, c1) + " | " + Utils.pf(" ", c2) + " | " +
                    Utils.pf(reqdstr, c3) + " | " + Utils.pf("", c4) + " | " +
                    Utils.pf(fSaldoStr, c5))
                #info+=Utils.pb(str(wkm.get("date"))+" free")
        info += Utils.pb(Utils.pfb(symbol="~"))
        info += Utils.pb(
            Utils.pf("End saldo:", c1) + Utils.pf("", c2 + c3 + c4 + 9) +
            " | " + Utils.pf(Utils.formatHM(ssSaldo), c5))
        info += Utils.pb(Utils.pfb(symbol="="))
        return info
예제 #20
0
 def __init__(self):
     self.l = logging.getLogger(__name__ + "." + self.__class__.__name__)
     self.historydir = settings.get("history_data")
     pass