...

Source file src/github.com/noirbizarre/gonja/ext/time/now.go

Documentation: github.com/noirbizarre/gonja/ext/time

     1  package time
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  
     8  	"github.com/pkg/errors"
     9  
    10  	arrow "github.com/bmuller/arrow/lib"
    11  
    12  	"github.com/noirbizarre/gonja/exec"
    13  	"github.com/noirbizarre/gonja/nodes"
    14  	"github.com/noirbizarre/gonja/parser"
    15  	"github.com/noirbizarre/gonja/tokens"
    16  )
    17  
    18  type TimeOffset struct {
    19  	Years   int
    20  	Months  int
    21  	Days    int
    22  	Hours   int
    23  	Minutes int
    24  	Seconds int
    25  }
    26  
    27  type NowStmt struct {
    28  	Location *tokens.Token
    29  	TZ       string
    30  	Format   string
    31  	Offset   *TimeOffset
    32  }
    33  
    34  func (stmt *NowStmt) Position() *tokens.Token { return stmt.Location }
    35  func (stmt *NowStmt) String() string {
    36  	t := stmt.Position()
    37  	return fmt.Sprintf("NowStmt(Line=%d Col=%d)", t.Line, t.Col)
    38  }
    39  
    40  func (stmt *NowStmt) Execute(r *exec.Renderer, tag *nodes.StatementBlock) error {
    41  	var now arrow.Arrow
    42  
    43  	cfg := r.Config.Ext["time"].(*Config)
    44  	format := cfg.DatetimeFormat
    45  
    46  	if cfg.Now != nil {
    47  		now = *cfg.Now
    48  	} else {
    49  		now = arrow.Now()
    50  	}
    51  
    52  	if stmt.Format != "" {
    53  		format = stmt.Format
    54  	}
    55  
    56  	now = now.InTimezone(stmt.TZ)
    57  
    58  	if stmt.Offset != nil {
    59  		offset := stmt.Offset
    60  		if offset.Years != 0 || offset.Months != 0 || offset.Days != 0 {
    61  			now = arrow.New(now.AddDate(offset.Years, offset.Months, offset.Days))
    62  		}
    63  		if offset.Hours != 0 {
    64  			now = now.AddHours(offset.Hours)
    65  		}
    66  		if offset.Minutes != 0 {
    67  			now = now.AddMinutes(offset.Minutes)
    68  		}
    69  		if offset.Seconds != 0 {
    70  			now = now.AddSeconds(offset.Seconds)
    71  		}
    72  	}
    73  
    74  	r.WriteString(now.CFormat(format))
    75  
    76  	return nil
    77  }
    78  
    79  func nowParser(p *parser.Parser, args *parser.Parser) (nodes.Statement, error) {
    80  	stmt := &NowStmt{
    81  		Location: p.Current(),
    82  	}
    83  
    84  	// Timezone
    85  	tz := args.Match(tokens.String)
    86  	if tz == nil {
    87  		return nil, args.Error(`now expect a timezone as first argument`, args.Current())
    88  	}
    89  	stmt.TZ = tz.Val
    90  
    91  	// Offset
    92  	if sign := args.Match(tokens.Add, tokens.Sub); sign != nil {
    93  		offset := args.Match(tokens.String)
    94  		if offset == nil {
    95  			return nil, args.Error("Expected an time offset.", args.Current())
    96  		}
    97  		timeOffset, err := parseTimeOffset(offset.Val, sign.Val == "+")
    98  		if err != nil {
    99  			return nil, errors.Wrapf(err, `Unable to parse time offset '%s'`, offset.Val)
   100  		}
   101  		stmt.Offset = timeOffset
   102  	}
   103  
   104  	// Format
   105  	if args.Match(tokens.Comma) != nil {
   106  		format := args.Match(tokens.String)
   107  		if format == nil {
   108  			return nil, args.Error("Expected a format string.", args.Current())
   109  		}
   110  		stmt.Format = format.Val
   111  	}
   112  
   113  	if !args.End() {
   114  		return nil, args.Error("Malformed now-tag args.", nil)
   115  	}
   116  
   117  	return stmt, nil
   118  }
   119  
   120  func parseTimeOffset(offset string, add bool) (*TimeOffset, error) {
   121  	pairs := strings.Split(offset, ",")
   122  	specs := map[string]int{}
   123  	for _, pair := range pairs {
   124  		splitted := strings.Split(pair, "=")
   125  		if len(splitted) != 2 {
   126  			return nil, errors.Errorf(`Expected a key=value pair, got '%s'`, pair)
   127  		}
   128  		unit := strings.TrimSpace(splitted[0])
   129  		value, err := strconv.Atoi(strings.TrimSpace(splitted[1]))
   130  		if err != nil {
   131  			return nil, errors.Wrap(err, `Unable to parse int`)
   132  		}
   133  		specs[unit] = value
   134  	}
   135  	to := &TimeOffset{}
   136  	for unit, value := range specs {
   137  		if !add {
   138  			value = -value
   139  		}
   140  		switch strings.ToLower(unit) {
   141  		case "year", "years":
   142  			to.Years = value
   143  		case "month", "months":
   144  			to.Months = value
   145  		case "day", "days":
   146  			to.Days = value
   147  		case "hour", "hours":
   148  			to.Hours = value
   149  		case "minute", "minutes":
   150  			to.Minutes = value
   151  		case "second", "seconds":
   152  			to.Seconds = value
   153  		default:
   154  			return nil, errors.Errorf(`Unknown unit '%s`, unit)
   155  		}
   156  	}
   157  	return to, nil
   158  }
   159  
   160  func init() {
   161  	Statements.Register("now", nowParser)
   162  }
   163  

View as plain text