Skip to content

Instantly share code, notes, and snippets.

@devlights
Forked from bessarabov/script.pl
Last active August 15, 2024 08:31
Show Gist options
  • Save devlights/7b866ce537987804ccb112b3f95c57d1 to your computer and use it in GitHub Desktop.
Save devlights/7b866ce537987804ccb112b3f95c57d1 to your computer and use it in GitHub Desktop.
Script to generate data shown in post 'At what time of day does famous programmers work? Part 2. Workweek vs Weekend.' — https://ivan.bessarabov.com/blog/famous-programmers-work-time-part-2-workweek-vs-weekend
/*
# Overview
git log --author="$GIT_USER_NAME" --format="%H %ai" の結果を集計するプログラムです。
# Usage
$ gcw --help
Usage of ./gcw:
-dir string
Path of git repository (default ".")
-tz string
Local Timezone (default "Asia/Tokyo")
-user string
Git username
$ gcw -user Gitユーザ名 -dir リポジトリのパス -tz ローカルタイムゾーン(デフォルトはAsia/Tokyo)
# Memo
このプログラムは、以下のブログ記事で利用されていたPerlスクリプトをGoに移植したものです。
元のスクリプトは
$ git log --author="$GIT_USER_NAME" --format="%H %ai" | perl script.pl
とパイプ経由で入力を受け取り、処理するようになっていましたが、Windows環境でも実行しやすいように
処理内で git コマンドも実行するように変更しています。
# REFERENCES
At what time of day do famous programmers work?
- https://ivan.bessarabov.com/blog/famous-programmers-work-time
At what time of day do famous programmers work? Part 2. Workweek vs Weekend.
- https://ivan.bessarabov.com/blog/famous-programmers-work-time-part-2-workweek-vs-weekend
Script to generate data shown in post 'At what time of day does famous programmers work? Part 2. Workweek vs Weekend.
- https://gist.github.com/bessarabov/30aee15c5a7c438fe5f9f3f623222b39
*/
package main
import (
"bufio"
"bytes"
"flag"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
)
type (
Args struct {
dir string
userName string
timeZone string
}
)
var (
args Args
)
func init() {
flag.StringVar(&args.dir, "dir", ".", "Path of git repository")
flag.StringVar(&args.userName, "user", "", "Git username")
flag.StringVar(&args.timeZone, "tz", "Asia/Tokyo", "Local Timezone")
}
func main() {
flag.Parse()
if args.userName == "" {
flag.PrintDefaults()
os.Exit(1)
}
if args.dir == "" {
args.dir = "."
}
if args.timeZone == "" {
args.timeZone = "Asia/Tokyo"
}
var (
absPath string
err error
)
absPath, err = filepath.Abs(args.dir)
if err != nil {
log.Fatalf("無効なディレクトリ: %s (%v)", args.dir, err)
}
args.dir = absPath
if err := run(); err != nil {
log.Fatal(err)
}
}
func run() error {
var (
output []byte
err error
)
output, err = exec.Command("git", "-C", args.dir, "log", fmt.Sprintf("--author=%s", args.userName), "--format=%H %ai").Output()
if err != nil {
return fmt.Errorf("gitコマンド実行エラー: %w", err)
}
var (
workweek = make(map[int]int)
weekend = make(map[int]int)
localTz *time.Location
)
localTz, err = time.LoadLocation("Asia/Tokyo")
if err != nil {
return fmt.Errorf("ローカルタイムゾーン取得エラー: %w", err)
}
var (
reader = bytes.NewReader(output)
scanner = bufio.NewScanner(reader)
)
for scanner.Scan() {
var (
line = scanner.Text()
fields = strings.Fields(line)
timestamp time.Time
localTime time.Time
)
if len(fields) < 2 {
continue
}
timestamp, err = time.Parse("2006-01-02 15:04:05 -0700", fields[1]+" "+fields[2]+" "+fields[3])
if err != nil {
fmt.Printf("日付解析エラー: %v\n", err)
continue
}
localTime = timestamp.In(localTz)
switch localTime.Weekday() {
case time.Saturday:
fallthrough
case time.Sunday:
weekend[localTime.Hour()]++
default:
workweek[localTime.Hour()]++
}
}
if err = scanner.Err(); err != nil {
return fmt.Errorf("読み取りエラー: %w", err)
}
printGraph(workweek, weekend)
return nil
}
func printGraph(workweek, weekend map[int]int) {
fmt.Printf("%6s %6s %-30s %6s %-30s\n", "hour", "", "Monday to Friday", "", "Saturday and Sunday")
var (
max = 0
hour = 0
)
for hour = 0; hour < 24; hour++ {
if max < workweek[hour] {
max = workweek[hour]
}
if max < weekend[hour] {
max = weekend[hour]
}
}
for hour = 0; hour < 24; hour++ {
var (
workweekCount = workweek[hour]
weekendCount = weekend[hour]
workweekStars = strings.Repeat("*", int(float64(workweekCount)/float64(max)*25))
weekendStars = strings.Repeat("*", int(float64(weekendCount)/float64(max)*25))
)
fmt.Printf("%02d %6d %-30s %6d %-30s\n", hour, workweekCount, workweekStars, weekendCount, weekendStars)
}
var (
totalWorkweek = sum(workweek)
totalWeekend = sum(weekend)
total = totalWorkweek + totalWeekend
)
fmt.Printf("\nTotal: %6d (%.1f%%) %6d (%.1f%%)\n",
totalWorkweek, float64(totalWorkweek)*100/float64(total),
totalWeekend, float64(totalWeekend)*100/float64(total))
}
func sum(m map[int]int) int {
var (
total = 0
)
for _, v := range m {
total += v
}
return total
}
#!/usr/bin/perl
# This script is made to show graphs with git commit time made on workweek vs weekend
#
# The desription of this script and results of its usage is avaliable at:
# https://ivan.bessarabov.com/blog/famous-programmers-work-time-part-2-workweek-vs-weekend
#
# usage:
#
# git log --author="Sebastian Riedel" --format="%H %ai" | perl script.pl
#
use strict;
use warnings FATAL => 'all';
use utf8;
use open qw(:std :utf8);
use feature qw(say);
use List::Util qw(max sum);
use Time::Local;
my %workweek;
my %weekend;
sub is_saturday_or_is_sunday {
my ($yyyy_mm_dd) = @_;
my ($year, $month, $day) = split /-/, $yyyy_mm_dd;
my $timestamp = timegm(
0,
0,
0,
$day,
$month - 1,
$year,
);
my $wday = [gmtime($timestamp)]->[6];
return $wday == 0 || $wday == 6;
}
while (my $line = <>) {
# 181971ff7774853fceb0459966177d51eeab032c 2019-04-26 19:53:58 +0200
my ($commit_hash, $date, $time, $timezone) = split / /, $line;
my ($hour, $minute, $second) = split /:/, $time;
$hour += 0;
if (is_saturday_or_is_sunday($date)) {
$weekend{$hour}++;
} else {
$workweek{$hour}++;
}
}
my $max = max(values(%workweek), values(%weekend));
my $format = "%6s %6s %-30s %6s %-30s",
say '';
say sprintf $format, 'hour', '', 'Monday to Friday', '', 'Saturday and Sunday';
foreach my $hour (0..23) {
$workweek{$hour} //= 0;
$weekend{$hour} //= 0;
say sprintf $format,
sprintf('%02d', $hour),
$workweek{$hour},
'*' x ($workweek{$hour} / $max * 25),
$weekend{$hour},
'*' x ($weekend{$hour} / $max * 25),
;
}
my $total_commits_workweek = sum(values %workweek);
my $total_commits_weekend = sum(values %weekend);
my $total_commits = $total_commits_workweek + $total_commits_weekend;
say '';
say sprintf $format,
'Total:',
$total_commits_workweek,
sprintf('(%.1f%%)', $total_commits_workweek * 100 / $total_commits),
$total_commits_weekend,
sprintf('(%.1f%%)', $total_commits_weekend* 100 / $total_commits),
;
say '';
@devlights
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment