Terminal Time Tracker

danigm's picture

Cuando se trabaja en una empresa es un tema recurrente el cálculo de tiempo dedicado a cada proyecto por parte del desarrollador.

Hay diferentes formas de hacerlo. La más simple sería mirando el reloj y haciendo un cálculo apróximado, el problema es que no tienes un registro de lo que has hecho.

Para el tracking de tiempo dedicado a un proyecto hay diferentes herramientas. Yo conocía gnotime que vale para lo que es, pero que no acaba de convencer.

Luego conocí Hamster, que es mucho más amigable, hace gráficas, informes y muchas polladas.

Yo en mi escritorio siempre tengo una terminal abierta, y últimamente me estoy dando cuenta de que las interfaces gráficas quitan mucho tiempo cuando no las necesitas, así que ayer decidí implementarme un time tracker de estos pero para terminal.

¿Cómo? Cojo python + vim, un poquito de sqlobject, se agita y aquí tenemos "Terminal Time Tracker".

En realidad son tres ficheros, aunque le he un instalador y desinstalador y polladas para que sea más simple de usar.

tttdb.py Una tabla para la base de datos.

  1. # Author: Daniel Garcia <dani@danigm.net>
  2. # License: GPLv3
  3.  
  4. from sqlobject import *
  5. import os
  6.  
  7. class Tracker(SQLObject):
  8. project = StringCol()
  9. task = StringCol()
  10. ticket = IntCol()
  11. start = DateTimeCol()
  12. end = DateTimeCol()
  13.  
  14. def get_hub():
  15. connection_string = 'sqlite://%s/devdata.sqlite' % os.getcwd()
  16. connection = connectionForURI(connection_string)
  17. sqlhub.processConnection = connection
  18.  
  19. return sqlhub
  20.  
  21. def create_db():
  22. # You need to create the database before.
  23. sqlhub = get_hub()
  24.  
  25. Tracker.createTable()

ttt.py Toda la chicha

  1. #!/usr/bin/python
  2.  
  3. # Author: Daniel Garcia <dani@danigm.net>
  4. # License: GPLv3
  5.  
  6. import datetime
  7. import time
  8. import sys
  9. import tttdb as db
  10. from tttdb import Tracker
  11.  
  12. sqlhub = db.get_hub()
  13.  
  14. def parse_time(time_seconds):
  15. hour = 0
  16. min = 0
  17. sec = time_seconds
  18. while sec >= 60:
  19. min += 1
  20. sec -= 60
  21. while min >= 60:
  22. hour += 1
  23. min -= 60
  24. time_str = '%02d:%02d:%02d' % (hour, min, sec)
  25. return time_str
  26.  
  27. def track(task, project='', ticket=0):
  28. today = datetime.datetime.now()
  29. tick = time.time()
  30. time_pass = 0
  31. try:
  32. while True:
  33. tick2 = time.time()
  34. time_pass = tick2 - tick
  35. cadena = '\rtracking: %(task)s %(project)s %(ticket)s %(time)s' % \
  36. {'time':parse_time(time_pass),
  37. 'task':task,
  38. 'project':project,
  39. 'ticket':ticket}
  40. sys.stdout.write(cadena)
  41. sys.stdout.flush()
  42. time.sleep(0.5)
  43. except:
  44. print '\n', 'Finalizando'
  45. end = datetime.datetime.now()
  46. db.Tracker(project=project,
  47. task=task,
  48. ticket=ticket,
  49. start=today,
  50. end=end)
  51.  
  52. def show(trackers):
  53. grouped = {}
  54. total = 0
  55. prev = ''
  56. for i in trackers:
  57. diff = i.end - i.start
  58. total += diff.seconds
  59. time_passed = parse_time(diff.seconds)
  60.  
  61. key = (i.task, i.project)
  62. if grouped.has_key(key):
  63. grouped[key] += diff.seconds
  64.  
  65. else:
  66. grouped[key] = diff.seconds
  67.  
  68. to_show = '%s | %-20s | %-40s | #%-6d | %s'
  69. to_show = to_show % (i.start.ctime(), i.project, i.task, i.ticket, time_passed)
  70. if prev != to_show[0:3]:
  71. prev = to_show[0:3]
  72. print ''
  73. print to_show
  74.  
  75. print ''
  76. for k,v in grouped.items():
  77. task, project = k
  78. time_passed = parse_time(v)
  79. print 'Tiempo para %-40s %s' % ('"'+task+'":', time_passed)
  80.  
  81. print '\nTotal: %s' % parse_time(total)
  82.  
  83. def show_today(delta=0):
  84. today = datetime.datetime.now() - datetime.timedelta(delta)
  85. yesterday = datetime.datetime(today.year, today.month, today.day)
  86. today_trackers = Tracker.select(Tracker.q.start > yesterday)
  87. show(today_trackers)
  88.  
  89. def show_project(project):
  90. project_trackers = Tracker.select(Tracker.q.project == project)
  91. sum = 0
  92. for i in project_trackers:
  93. sum += (i.end - i.start).seconds
  94.  
  95. print 'Tiempo para "%s": %s' % (project, parse_time(sum))
  96.  
  97. def show_all():
  98. all = Tracker.select()
  99. show(all)
  100.  
  101. def show_week():
  102. show_today(6)
  103.  
  104. def show_week_grouped():
  105. show_today_grouped(6)
  106.  
  107. def show_today_grouped(delta=0):
  108. today = datetime.datetime.now() - datetime.timedelta(delta)
  109. yesterday = datetime.datetime(today.year, today.month, today.day)
  110. today_trackers = Tracker.select(Tracker.q.start > yesterday)
  111. show_grouped(today_trackers)
  112.  
  113. def show_grouped(trackers):
  114. projects = {}
  115. total = 0
  116. for i in trackers:
  117. diff = (i.end - i.start).seconds
  118. total += diff
  119. if projects.has_key(i.project):
  120. projects[i.project] += diff
  121. else:
  122. projects[i.project] = diff
  123.  
  124. print ''
  125. for k,v in projects.items():
  126. p = '"' + k + '":'
  127. print 'Tiempo para %-20s %s' % (p, parse_time(v))
  128.  
  129. print '\nTotal: %s' % parse_time(total)
  130.  
  131. if __name__ == '__main__':
  132. help = '''
  133. %s tarea [proyecto] [ticket]
  134. '''
  135.  
  136. task, project, ticket = '','',0
  137. args = sys.argv[1:]
  138. if ('-h' in args) or ('--help' in args) or (len(args) == 0):
  139. print help % sys.argv[0]
  140. sys.exit()
  141. if len(args) >= 1:
  142. task = args[0]
  143. if len(args) >= 2:
  144. project = args[1]
  145. if len(args) >= 3:
  146. ticket = int(args[2])
  147.  
  148. track(task, project, ticket)

show.py Para ver el registro

  1. #!/usr/bin/python
  2.  
  3. # Author: Daniel Garcia <dani@danigm.net>
  4. # License: GPLv3
  5.  
  6. import sys
  7. import ttt
  8.  
  9. if __name__ == '__main__':
  10. help = '''
  11. %s [opcion]
  12.  
  13. opciones:
  14. -g muestra agrupados por proyecto
  15. -w muestra la ultima semana
  16. -gw muestra la ultima semana agrupado por proyecto
  17. -a muestra todo
  18.  
  19. si no se especifica opcion muestra las tareas de hoy
  20. '''
  21. args = sys.argv[1:]
  22. if ('-h' in args) or ('--help' in args):
  23. print help % sys.argv[0]
  24.  
  25. elif '-g' in args:
  26. # show grouped by project
  27. ttt.show_today_grouped()
  28. elif '-w' in args:
  29. ttt.show_week()
  30. elif '-gw' in args:
  31. # show grouped by project
  32. ttt.show_week_grouped()
  33. elif '-a' in args:
  34. ttt.show_all()
  35. else:
  36. ttt.show_today()

El código se puede pillar de mi repositorio personal:

  bzr branch http://repo.danigm.net/ttt

O del fichero tar.gz que adjunto aquí.

Para usarlo, tienes que tener instalado sqlobject y se instalaría ejecutando el script install.sh (hace una llamada a un comando con sudo). Esto te crea un directorio en $HOME/.ttt donde mete la base de datos y los scripts en python, y además copia t3 y t3show a /usr/local/bin para que puedas ejecutar los comandos sin modificar tu path.

Se usa de la siguiente manera:

  t3 "Escribiendo un post"

Y en la terminal se muestra el tiempo que vas dedicando a esta tarea. Para terminar tan solo hay que pulsar ctrl+c.
Además de una tarea se puede especificar un proyecto y un número para referenciarlo en el sistema de tickets que uses.

sintaxis:
  t3 tarea [proyecto] [ticket]
  t3 -h
ejemplo:
  t3 "plugin para jisko" "sweetter" 235879

Y para mostrar el resultado se usa t3show

Wed Sep 24 20:34:01 2008 | ttt                  | publicando                               | #0      | 00:00:06
Wed Sep 24 20:34:04 2008 | sweetter             | plugin para jisko                        | #235879 | 00:00:08
Wed Sep 24 20:34:18 2008 | ttt                  | publicando                               | #0      | 00:00:05

Tiempo para "plugin para jisko":                     00:00:08
Tiempo para "publicando":                            00:00:11

Total: 00:00:19

Con las opciones -g -w -gw -a que muestran agrupado por proyecto, la última semana, por proyecto en la última semana y todo respectivamente. Además de mostrar el día actual si no se le pasa ningún parametro y la ayuda con el comando -h.