using date-time in emacs spreadsheets - emacs

I'm just starting to use ses-mode in emacs, and I plan to use it with timestamps, but I do not manage to have them parsed in a way that I can then use.
I'm taking measurements on three days of the week, so my distances between one measurement and the other is either 2 or 3 days. I chose to use ses-mode in emacs because it runs on all of my computers, including the phone.
my spreadsheet contains datestamp, conductivity, temperature, and gallon count, a couple of subsequent lines would look like this:
2014-10-03 2.95 33.4 4031070
2014-10-06 3.07 33.5 4086930
2014-10-08 2.97 33.6 4119590
I would add two more columns, the first with the difference of days between the readings, the second with the "gallon-per-day" value.
I do not manage to have the string timestamp parsed into a format where I can do computations, staying within a simple emacs spreadsheet (SES).
I've tried date-to-time, but it always returns the same value (14445 17280).
parse-time-string gives me a 9-tuple which I can't directly pass to format-time-string.

The function encode-time helps:
(let ((l (parse-time-string "2014-09-12")))
(format-time-string "%d %m %Y" (encode-time 0 0 0 (nth 3 l) (nth 4 l) (nth 5 l))))
The following version uses cl-flet to avoid doubling of code if the encoding is needed multiple times. If you need the encoding also in other functions you can use defun instead of cl-flet.
(eval-when (compile) (require 'cl)) ;; for cl-flet
(let ((A2 "2014-10-08") ;; just for testing
(A1 "2014-10-03")) ;; just for testing
(cl-flet ((encode (str)
(let ((l (parse-time-string str)))
(encode-time 0 0 0 (nth 3 l) (nth 4 l) (nth 5 l)))))
(let* ((t-prev (encode A1))
(t-this (encode A2)))
(/ (time-to-seconds (time-subtract t-this t-prev)) (* 24 60 60)))))
As a function:
(eval-when (compile) (require 'cl)) ;; for cl-flet
(defun day-diff (date1 date2)
"Calculate the difference of dates in days between DATE1-STR and DATE2-STR."
(interactive "sDate1:\nsDate2:")
(cl-flet ((encode (str)
(let ((l (parse-time-string str)))
(encode-time 0 0 0 (nth 3 l) (nth 4 l) (nth 5 l)))))
(setq date1 (encode date1)
date2 (encode date2))
(let ((ret (/ (time-to-seconds (time-subtract date1 date2)) (* 24 60 60))))
(when (called-interactively-p 'any)
(message "Day difference: %s" ret))
ret)))
(put 'day-diff 'safe-function t)
An alternative using calc would be:
(require 'calc)
(defun day-diff (date1 date2)
"Calculate the difference of dates in days between DATE1-STR and DATE2-STR."
(interactive "sDate1:\nsDate2:")
(let ((ret (string-to-number (calc-eval (format "<%s>-<%s>" date1 date2)))))
(when (called-interactively-p 'any)
(message "Day difference: %s" ret))
ret))
If you omit the nice-to-have features this becomes almost a simple cell formula: (string-to-number (calc-eval (format "<%s>-<%s>" A1 A2))).
If you want to save the stuff in the spreadsheet you can put the defun in table cell A1. A more simple example:
(progn (defun day-diff (date1 date2) (string-to-number (calc-eval (format "<%s>-<%s>" date1 date2)))) (put 'day 'safe-function t) "Actual header")
To have a more convenient editing possibility you can switch to M-x lisp-mode.
There you find
^L
(ses-cell A1 "Actual Header" (progn (defun day-diff (date1 date2) (string-to-number (calc-eval (format "<%s>-<%s>" date1 date2)))) (put 'day 'safe-function t) "Actual header") nil nil)
which you can edit. But do not insert linebreaks! ses identifies cell-positions with line numbers in that file!
Another nice alternative is to put the definition of your function into the file-local variable list.
Switch to lisp-interaction mode by M-x lisp-interaction-mode.
Go to the end of the file. There you find the lines:
;; Local Variables:
;; mode: ses
;; End:
Add your function definition as eval to this list:
;; Local Variables:
;; mode: ses
;; eval:
;; (progn
;; (defun day-diff (date1 date2)
;; (string-to-number (calc-eval (format "<%s>-<%s>" date1 date2))))
;; (put 'day-diff 'safe-function t))
;; End:
You can add the progn without the comment characters ;. In this case even indentation works. Afterwards you can call comment-region for the progn.
You can save the file and run M-x normal-mode. Afterwards the function is defined and you can use it in the spreadsheet.

Related

Function to determine holiday in elisp

It's there any function to determine current system date is holiday or not in elisp.
function like this.
(is-holiday (current-time))
The answer requires that the user set up a calendar of predefined holidays, like this example. I have included a test holiday for May 9 -- if the user wishes to test out this function on any day other than May 9, the user may wish to change the Arbitrary Test Holiday to whatever day the test is being performed -- after the function has been tested, the test entry can be removed.
For examples of how to format the holidays, please refer to the doc-string for the variable calendar-holidays within the library holidays.el -- e.g., holiday-fixed; holiday-float; holiday-sexp; (lunar-phases); (solar-equinoxes-solstices); holiday-hebrew; holiday-islamic; holiday-bahai; holiday-julian; holiday-chinese; etc.
How can you try out this example?: Block/copy/paste the code into your *scratch* buffer; and type M-x eval-buffer RET; and then type M-x is-holiday RET. It is a fully functional working draft. If you decide that you don't like it after you try it, just restart Emacs and you'll be back to where you were before you tried it.
The testing that was performed was done with the most recent public release of Emacs: GNU Emacs 24.4.1 (x86_64-apple-darwin10.8.0, NS apple-appkit-1038.36) of 2014-10-20 on builder10-6.porkrind.org.
(require 'holidays)
(defcustom my-custom-holiday-list (mapcar 'purecopy '(
(holiday-fixed 1 1 "New Year's Day")
(holiday-float 1 1 3 "Martin Luther King Day")
(holiday-float 2 1 3 "President's Day")
(holiday-float 5 1 -1 "Memorial Day")
;; ARBITRARY TEST HOLIDAY -- MAY 9
(holiday-fixed 5 9 "Arbitrary Test Holiday -- May 9")
(holiday-fixed 7 4 "Independence Day")
(holiday-float 9 1 1 "Labor Day")
(holiday-float 10 1 2 "Columbus Day")
(holiday-fixed 11 11 "Veteran's Day")
(holiday-float 11 4 4 "Thanksgiving")
(holiday-fixed 12 25 "Christmas")
(solar-equinoxes-solstices)
(holiday-sexp calendar-daylight-savings-starts
(format "Daylight Saving Time Begins %s"
(solar-time-string
(/ calendar-daylight-savings-starts-time (float 60))
calendar-standard-time-zone-name)))
(holiday-sexp calendar-daylight-savings-ends
(format "Daylight Saving Time Ends %s"
(solar-time-string
(/ calendar-daylight-savings-ends-time (float 60))
calendar-daylight-time-zone-name))) ))
"Custom holidays defined by the user."
:type 'sexp
:group 'holidays)
(defun is-holiday ()
"Is today a holiday?"
(interactive)
(let* (
(d1 (time-to-days (current-time)))
(date (calendar-gregorian-from-absolute d1))
ee
res-holidays
(displayed-month (nth 0 date))
(displayed-year (nth 2 date))
(holiday-list
(dolist (p my-custom-holiday-list res-holidays)
(let* (h)
(when (setq h (eval p))
(setq res-holidays (append h res-holidays)))))) )
(mapcar
(lambda (x)
(let ((txt (format "%s -- %s" (car x) (car (cdr x)))))
(when (eq d1 (calendar-absolute-from-gregorian (car x)))
(push txt ee))))
holiday-list)
(if ee
(message "The following holiday(s) is/are today: %s" (nreverse ee))
(message "Today is not a holiday."))))

How do I find and insert the average of multiple lines in Emacs / Elisp?

I have a file that looks similar to:
AT 4
AT 5.6
AT 7.2
EG 6
EG 6
S 2
OP 3
OP 1.2
OP 40
and I want to compute the average (I've just made these averages up) for each of the titles and output something like:
AT 5.42
EG 6
S 2
OP 32.1
The file is in order, so all headings will be right under each other, but there are a varying amount of headings. eg. AT has three, but S only has one.
How would I sum together each of these lines, divide by the number of lines, and then replace all of the lines in emacs / elisp?
I decided to try to solve this question while still learning elisp myself. There is perhaps more efficient ways to solve this.
After defining the function, you'll want to set the region around the scores. (If the whole file, then M-<, C-SPC, M->) I figured this would be cleanest since your scores may be in the middle of other text. My function will compute the averages and then insert the answer at the end of the region.
(defun my/averages (beg end)
(interactive "r")
(let ((avgs (make-hash-table :test 'equal))
(answer "")
(curval nil)
(key nil)
(val nil))
; Process each line in region
(save-excursion
(goto-char beg)
(while (< (point) end)
; split line
(let ((split-line
(split-string
(buffer-substring-no-properties
(line-beginning-position) (line-end-position)))))
(setq
key (car split-line)
val (string-to-number (cadr split-line))
curval (gethash key avgs '(0 . 0)))
(puthash key (cons (+ (car curval) 1) (+ (cdr curval) val )) avgs))
; Advance to next line
(forward-line))
; Accumulate answer string
(maphash
(lambda (k v)
(setq answer
(concat answer "\n" k " "
(number-to-string (/ (cdr v) (car v))))))
avgs)
(end-of-line)
(insert answer))))
As a warning, I have zero error checking for lines that do not strictly meet your formatting.
You need libraries dash, s, f, and their functions -map, -sum, -group-by, s-split, f-read-text.
;; average
(defun avg (values)
(/ (-sum values) (length values)))
(-map (lambda (item)
(list (car item)
(avg (-map (lambda (x)
(string-to-number (cadr x)))
(cdr item)))))
(-group-by (lambda (item)
(car item))
(-map (lambda (line)
(s-split " " line t))
(s-split "[\n\r]"
(f-read-text "file.txt")
t))))
Presuming your file is called "file.txt", the code above returns (("AT" 5.6000000000000005) ("EG" 6) ("S" 2) ("OP" 14.733333333333334)).
After that you can convert that into text:
(s-join "\n"
(-map (lambda (item)
(s-join " "
(list (car item)
(number-to-string (cadr item)))))
This string you can write into file using f-write-text. Don't forget you can format ugly floating-point numbers like that:
(format "%.2f" 3.33333333) ; => "3.33"

Custom function for next / previous month in agenda view and the calendar

I'm looking for a way to select next or previous month in both agenda view and the calendar. I've written a concept/prototype function (below), but it doesn't calculate the next or previous months and I would also need to rewrite the function every month.
The date format for the org-agenda-month-view is different than the date format for calendar-other-month. Further down below are some functions that are related to what I'm trying to accomplish -- e.g., calendar already has the ability to move forward or backward by month.
I think what may be needed is a function that identifies the month being viewed and then adds plus-or-minus one month (in the proper format) when hitting the next or previous button.
(defun lawlist-org-agenda-view-mode-dispatch ()
"Select the month in agenda view."
(interactive)
(message "View: [7] JUL | [8] AUG | [9] SEP | [o]CT | [n]OV | [d]EC ")
(let ((a (read-char-exclusive)))
(case a
(?7
(org-agenda nil "a")
(org-agenda-month-view 201307)
(calendar)
(calendar-other-month 7 2013)
(lawlist-org-agenda-view-mode-dispatch))
(?8
(org-agenda nil "a")
(org-agenda-month-view 201308)
(calendar)
(calendar-other-month 8 2013)
(lawlist-org-agenda-view-mode-dispatch))
(?9
(org-agenda nil "a")
(org-agenda-month-view 201309)
(calendar)
(calendar-other-month 9 2013)
(lawlist-org-agenda-view-mode-dispatch))
(?o
(org-agenda nil "a")
(org-agenda-month-view 201310)
(calendar)
(calendar-other-month 10 2013)
(lawlist-org-agenda-view-mode-dispatch))
(?n
(org-agenda nil "a")
        (org-agenda-month-view 201311)
(calendar)
(calendar-other-month 11 2013)
(lawlist-org-agenda-view-mode-dispatch))
(?d
(org-agenda nil "a")
(org-agenda-month-view 201312)
(calendar)
(calendar-other-month 12 2013)
(lawlist-org-agenda-view-mode-dispatch))
(?q (message "Abort"))
(otherwise (error "Either press \"q\" to quit, or select another option." )))))
Here are some related functions I've extracted from cal-move.el and calendar.el:
(defun calendar-other-month (month year &optional event)
"Display a three-month calendar centered around MONTH and YEAR.
EVENT is an event like `last-nonmenu-event'."
(interactive (let ((event (list last-nonmenu-event)))
(append (calendar-read-date 'noday) event)))
(save-selected-window
(and event
(setq event (event-start event))
(select-window (posn-window event)))
(unless (and (= month displayed-month)
(= year displayed-year))
(let ((old-date (calendar-cursor-to-date))
(today (calendar-current-date)))
(calendar-generate-window month year)
(calendar-cursor-to-visible-date
(cond
((calendar-date-is-visible-p old-date) old-date)
((calendar-date-is-visible-p today) today)
(t (list month 1 year))))))))
;;;###cal-autoload
(defun calendar-forward-month (arg)
"Move the cursor forward ARG months.
Movement is backward if ARG is negative."
(interactive "p")
(calendar-cursor-to-nearest-date)
(let* ((cursor-date (calendar-cursor-to-date t))
(month (calendar-extract-month cursor-date))
(day (calendar-extract-day cursor-date))
(year (calendar-extract-year cursor-date))
(last (progn
(calendar-increment-month month year arg)
(calendar-last-day-of-month month year)))
(day (min last day))
;; Put the new month on the screen, if needed, and go to the new date.
(new-cursor-date (list month day year)))
(if (not (calendar-date-is-visible-p new-cursor-date))
(calendar-other-month month year))
(calendar-cursor-to-visible-date new-cursor-date))
(run-hooks 'calendar-move-hook))
;;;###cal-autoload
(defun calendar-backward-month (arg)
"Move the cursor backward by ARG months.
Movement is forward if ARG is negative."
(interactive "p")
(calendar-forward-month (- arg)))
;;;###cal-autoload
(defun calendar-forward-year (arg)
"Move the cursor forward by ARG years.
Movement is backward if ARG is negative."
(interactive "p")
(calendar-forward-month (* 12 arg)))
;;;###cal-autoload
(defun calendar-backward-year (arg)
"Move the cursor backward ARG years.
Movement is forward is ARG is negative."
(interactive "p")
(calendar-forward-month (* -12 arg)))
;;;###cal-autoload
(defun calendar-scroll-left (&optional arg event)
"Scroll the displayed calendar left by ARG months.
If ARG is negative the calendar is scrolled right. Maintains the relative
position of the cursor with respect to the calendar as well as possible.
EVENT is an event like `last-nonmenu-event'."
(interactive (list (prefix-numeric-value current-prefix-arg)
last-nonmenu-event))
(unless arg (setq arg 1))
(save-selected-window
;; Nil if called from menu-bar.
(if (setq event (event-start event)) (select-window (posn-window event)))
(calendar-cursor-to-nearest-date)
(unless (zerop arg)
(let ((old-date (calendar-cursor-to-date))
(today (calendar-current-date))
(month displayed-month)
(year displayed-year))
(calendar-increment-month month year arg)
(calendar-generate-window month year)
(calendar-cursor-to-visible-date
(cond
((calendar-date-is-visible-p old-date) old-date)
((calendar-date-is-visible-p today) today)
(t (list month 1 year))))))
(run-hooks 'calendar-move-hook)))
(define-obsolete-function-alias
'scroll-calendar-left 'calendar-scroll-left "23.1")
;;;###cal-autoload
(defun calendar-scroll-right (&optional arg event)
"Scroll the displayed calendar window right by ARG months.
If ARG is negative the calendar is scrolled left. Maintains the relative
position of the cursor with respect to the calendar as well as possible.
EVENT is an event like `last-nonmenu-event'."
(interactive (list (prefix-numeric-value current-prefix-arg)
last-nonmenu-event))
(calendar-scroll-left (- (or arg 1)) event))
(define-obsolete-function-alias
'scroll-calendar-right 'calendar-scroll-right "23.1")
Here's my take:
(defvar lawlist-month)
(defun lawlist-org-agenda-view-mode-dispatch ()
"Select the month in agenda view."
(interactive)
(message "View: [1-9] [o]CT [n]OV [d]EC, j(next), k(prev).")
(let* ((a (read-char-exclusive))
(month (case a
(?o 10)
(?n 11)
(?d 12)
(?j (or (and lawlist-month (mod (1+ lawlist-month) 12)) 1))
(?k (or (and lawlist-month (mod (1- lawlist-month) 12)) 1))
(t (and (> a ?0) (<= a ?9) (- a ?0))))))
(if (setq lawlist-month month)
(let ((year (nth 5 (decode-time (current-time)))))
(org-agenda nil "a")
(org-agenda-month-view
(read (format "%d%02d" year month)))
(calendar)
(calendar-other-month month year)
(lawlist-org-agenda-view-mode-dispatch))
(message "Aborted"))))
It still misses some functionality like saving the window configuration and
recovering on abort.
UPD
The updated code can be found in this gist.
I've added other years besides current, with support for j/k, as well as h/l for years.

Emacs Auto Load Color Theme by Time

Can I let Emacs automatically load theme ? or do certain command at customized time ? Say what I want is to M-x load-theme RET solarized-light when I am at office at 9:00am and M-x laod-theme RET solarized-dark when I am back home and continued on emacs at 8:00pm.
To expand on #Anton Kovalenko's answer, you can get the current time using the current-time-string elisp function and extracting the current time of day in hours.
If you want to write a full implementation, you could do something like (Warning, not debugged):
;; <Color theme initialization code>
(setq current-theme '(color-theme-solarized-light))
(defun synchronize-theme ()
(setq hour
(string-to-number
(substring (current-time-string) 11 13)))
(if (member hour (number-sequence 6 17))
(setq now '(color-theme-solarized-light))
(setq now '(color-theme-solarized-dark)))
(if (equal now current-theme)
nil
(setq current-theme now)
(eval now) ) ) ;; end of (defun ...
(run-with-timer 0 3600 synchronize-theme)
For more info on the functions used, see the following sections of the emacs manual:
Time of day
Strings
String Conversions
Idle Timers
Contains
Number Sequence
Another (very elegant) solution is theme-changer.
Given a location and day/night color themes, this file provides a change-theme function that selects the appropriate theme based on whether it is day or night. It will continue to change themes at sunrise and sunset. To install:
Set the location:
(setq calendar-location-name "Dallas, TX")
(setq calendar-latitude 32.85)
(setq calendar-longitude -96.85)
Specify the day and night themes:
(require 'theme-changer)
(change-theme 'tango 'tango-dark)
The project is hosted on Github, and can be installed through melpa.
You can use this snippet of code to do what you want.
(defvar install-theme-loading-times nil
"An association list of time strings and theme names.
The themes will be loaded at the specified time every day.")
(defvar install-theme-timers nil)
(defun install-theme-loading-at-times ()
"Set up theme loading according to `install-theme-loading-at-times`"
(interactive)
(dolist (timer install-theme-timers)
(cancel-timer timer))
(setq install-theme-timers nil)
(dolist (time-theme install-theme-loading-times)
(add-to-list 'install-theme-timers
(run-at-time (car time-theme) (* 60 60 24) 'load-theme (cdr time-theme)))))
Just customize the variable install-theme-loading-times as desired:
(setq install-theme-loading-times '(("9:00am" . solarized-light)
("8:00pm" . solarized-dark)))
You can start with run-with-timer function:
(run-with-timer SECS REPEAT FUNCTION &rest ARGS)
Perform an action after a delay of SECS seconds.
Repeat the action every REPEAT seconds, if REPEAT is non-nil.
SECS and REPEAT may be integers or floating point numbers.
The action is to call FUNCTION with arguments ARGS.
This function returns a timer object which you can use in `cancel-timer'.
Schedule a function to run every minute or so, which will check
current time and call load-theme when appropriate (don't switch
theme every minute, even if it's reloading the current theme).
Found this simple code that works for doom emacs. Put this in the config file:
(load-theme 'solarized-light t t) ;;load light theme
(run-at-time "09:00" (* 60 60 24) (lambda () (enable-theme 'solarized-light)))
(load-theme 'solarized-dark t t) ;;load dark theme
(run-at-time "20:00" (* 60 60 24) (lambda () (enable-theme 'solarized-dark)))
replace light and dark themes with your choice. time can also be changed from 9am/8pm in 24-hour format.
source and credit: https://parasurv.neocities.org/emacs/change-emacs-theme-depending-on-time.html
This implementation changes theme based on sunrise and sunset times of the latitude and longitude you provide. The only dependency is solar.el which is released with Emacs (IIRC).
(I think the code can probably be shorter here.)
;; theme changing at sunrises and sunsets according to lat and long
(require 'solar)
(defun today-date-integer (offset)
"Returns today's date in a list of integers, i.e. month, date, and year, in system time."
(let* ((date (mapcar
(lambda (pattern)
(string-to-number (format-time-string pattern)))
'("%m" "%d" "%Y"))))
(setcar
(nthcdr
1
date)
(+ offset (nth 1 date)))
date))
(defun current-time-decimal ()
(let* ((current-min-fraction (/ (string-to-number (format-time-string "%M")) 60.0))
(current-hour (string-to-number (format-time-string "%H"))))
(+ current-hour current-min-fraction)))
(defun next-alarm-time (sunrise-time sunset-time)
(let* ((current-time (current-time-decimal)))
(cond ((< current-time sunrise-time)
(- sunrise-time current-time))
((and (>= current-time sunrise-time)
(< current-time sunset-time))
(- sunset-time current-time))
((>= current-time sunset-time)
(let ((tomorrow-sunrise-time (car (car (solar-sunrise-sunset (today-date-integer 1))))))
(- (+ 24 tomorrow-sunrise-time) current-time))))))
(defun to-seconds (hour) (* hour 60 60))
(defun change-theme (light-theme dark-theme coor)
(let* ((_ (setq calendar-latitude (car coor)))
( _ (setq calendar-longitude (nth 1 coor)))
(today-date (today-date-integer 0))
(sunrise-sunset-list (solar-sunrise-sunset today-date))
(sunrise-time (car (car sunrise-sunset-list)))
(sunset-time (car (nth 1 sunrise-sunset-list)))
(current-time (current-time-decimal))
(current-theme (if (or (< current-time sunrise-time) (> current-time sunset-time))
dark-theme
light-theme))
(next-alarm-t (next-alarm-time sunrise-time sunset-time)))
(cancel-function-timers 'change-theme)
(load-theme current-theme t)
(run-at-time
(to-seconds next-alarm-t) nil 'change-theme light-theme dark-theme coor)))
(change-theme 'solarized-gruvbox-light 'solarized-gruvbox-dark '(47.6062 -122.3321))

Emacs calendar: show more than 3 months?

In Emacs, when you display the calendar with M-x calendar, you get a three-month display – last month, this month, and next month – in a new window that's just 8 lines tall.
Is it possible to generate a twelve-month calendar in a full-size window?
12-MONTH CALENDAR -- SCROLLS BY MONTH (FORWARDS / BACKWARDS)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; ;;;
;;; Scroll a yearly calendar by month -- in a forwards or backwards direction. ;;;
;;; ;;;
;;; To try out this example, evaluate the entire code snippet and type: ;;;
;;; ;;;
;;; M-x year-calendar ;;;
;;; ;;;
;;; To scroll forward by month, type the key: > ;;;
;;; ;;;
;;; To scroll backward by month, type the key: < ;;;
;;; ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(eval-after-load "calendar" '(progn
(define-key calendar-mode-map "<" 'lawlist-scroll-year-calendar-backward)
(define-key calendar-mode-map ">" 'lawlist-scroll-year-calendar-forward) ))
(defmacro lawlist-calendar-for-loop (var from init to final do &rest body)
"Execute a for loop.
Evaluate BODY with VAR bound to successive integers from INIT to FINAL,
inclusive. The standard macro `dotimes' is preferable in most cases."
`(let ((,var (1- ,init)))
(while (>= ,final (setq ,var (1+ ,var)))
,#body)))
(defun year-calendar (&optional month year)
"Generate a one (1) year calendar that can be scrolled by month in each direction.
This is a modification of: http://homepage3.nifty.com/oatu/emacs/calendar.html
See also: http://ivan.kanis.fr/caly.el"
(interactive)
(require 'calendar)
(let* ((current-year (number-to-string (nth 5 (decode-time (current-time)))))
(month (if month month
(string-to-number
(read-string "Please enter a month number (e.g., 1): " nil nil "1"))))
(year (if year year
(string-to-number
(read-string "Please enter a year (e.g., 2014): "
nil nil current-year)))))
(switch-to-buffer (get-buffer-create calendar-buffer))
(when (not (eq major-mode 'calendar-mode))
(calendar-mode))
(setq displayed-month month)
(setq displayed-year year)
(setq buffer-read-only nil)
(erase-buffer)
;; horizontal rows
(lawlist-calendar-for-loop j from 0 to 3 do
;; vertical columns
(lawlist-calendar-for-loop i from 0 to 2 do
(calendar-generate-month
;; month
(cond
((> (+ (* j 3) i month) 12)
(- (+ (* j 3) i month) 12))
(t
(+ (* j 3) i month)))
;; year
(cond
((> (+ (* j 3) i month) 12)
(+ year 1))
(t
year))
;; indentation / spacing between months
(+ 5 (* 25 i))))
(goto-char (point-max))
(insert (make-string (- 10 (count-lines (point-min) (point-max))) ?\n))
(widen)
(goto-char (point-max))
(narrow-to-region (point-max) (point-max)))
(widen)
(goto-char (point-min))
(setq buffer-read-only t)))
(defun lawlist-scroll-year-calendar-forward (&optional arg event)
"Scroll the yearly calendar by month in a forward direction."
(interactive (list (prefix-numeric-value current-prefix-arg)
last-nonmenu-event))
(unless arg (setq arg 1))
(save-selected-window
(if (setq event (event-start event)) (select-window (posn-window event)))
(unless (zerop arg)
(let ((month displayed-month)
(year displayed-year))
(calendar-increment-month month year arg)
(year-calendar month year)))
(goto-char (point-min))
(run-hooks 'calendar-move-hook)))
(defun lawlist-scroll-year-calendar-backward (&optional arg event)
"Scroll the yearly calendar by month in a backward direction."
(interactive (list (prefix-numeric-value current-prefix-arg)
last-nonmenu-event))
(lawlist-scroll-year-calendar-forward (- (or arg 1)) event))
There doesn't seem to be an easy way to do this. I was able to knock up the following code, which will show all twelve months, in a row, in a separate frame.
(require 'cl)
(require 'calendar)
(defun twelve-month-calendar ()
(interactive)
(let ((calendar-buffer (get-buffer-create "12-month calendar"))
(month 12)
(year 2012))
(set-buffer calendar-buffer)
(setq calendar-frame (make-frame))
(make-variable-buffer-local 'font-lock-face)
(set-face-attribute 'default calendar-frame :height 70)
(set-frame-width calendar-frame 300)
(erase-buffer)
(dotimes (i 12)
(calendar-generate-month month year 0)
(calendar-increment-month month year -1))
(calendar-mode)))
You might need to tweak it a bit, depending on your screen/font size.
I modified "12-MONTH CALENDAR -- SCROLLS BY MONTH (FORWARDS / BACKWARDS)" answer and adapted it to Emacs post 23.3 version - no calendar-for-loop macro - and changed scroll from by one month to by one year. This version show entire calendar for current year. Going backwards which < and forwards > by one year. It doesn't show on full screen, but half screen, which make it easy to use when working which vertical splits and it's more like extended version of build in calendar.
;; https://stackoverflow.com/questions/9547912/emacs-calendar-show-more-than-3-months
(defun farynaio/year-calendar (&optional year)
"Generate a one year calendar that can be scrolled by year in each direction.
This is a modification of: http://homepage3.nifty.com/oatu/emacs/calendar.html
See also: https://stackoverflow.com/questions/9547912/emacs-calendar-show-more-than-3-months"
(interactive)
(require 'calendar)
(let* (
(current-year (number-to-string (nth 5 (decode-time (current-time)))))
(month 0)
(year (if year year (string-to-number (format-time-string "%Y" (current-time))))))
(switch-to-buffer (get-buffer-create calendar-buffer))
(when (not (eq major-mode 'calendar-mode))
(calendar-mode))
(setq displayed-month month)
(setq displayed-year year)
(setq buffer-read-only nil)
(erase-buffer)
;; horizontal rows
(dotimes (j 4)
;; vertical columns
(dotimes (i 3)
(calendar-generate-month
(setq month (+ month 1))
year
;; indentation / spacing between months
(+ 5 (* 25 i))))
(goto-char (point-max))
(insert (make-string (- 10 (count-lines (point-min) (point-max))) ?\n))
(widen)
(goto-char (point-max))
(narrow-to-region (point-max) (point-max)))
(widen)
(goto-char (point-min))
(setq buffer-read-only t)))
(defun farynaio/scroll-year-calendar-forward (&optional arg event)
"Scroll the yearly calendar by year in a forward direction."
(interactive (list (prefix-numeric-value current-prefix-arg)
last-nonmenu-event))
(unless arg (setq arg 0))
(save-selected-window
(if (setq event (event-start event)) (select-window (posn-window event)))
(unless (zerop arg)
(let* (
(year (+ displayed-year arg)))
(jarfar/year-calendar year)))
(goto-char (point-min))
(run-hooks 'calendar-move-hook)))
(defun farynaio/scroll-year-calendar-backward (&optional arg event)
"Scroll the yearly calendar by year in a backward direction."
(interactive (list (prefix-numeric-value current-prefix-arg)
last-nonmenu-event))
(farynaio/scroll-year-calendar-forward (- (or arg 1)) event))
(define-key calendar-mode-map "<" 'farynaio/scroll-year-calendar-backward)
(define-key calendar-mode-map ">" 'farynaio/scroll-year-calendar-forward)
(defalias 'year-calendar 'farynaio/year-calendar)
It's not easy to do this, the code to generate calendar is:
(defun calendar-generate (month year)
"Generate a three-month Gregorian calendar centered around MONTH, YEAR."
;; A negative YEAR is interpreted as BC; -1 being 1 BC, and so on.
;; Note that while calendars for years BC could be displayed as it
;; stands, almost all other calendar functions (eg holidays) would
;; at best have unpredictable results for such dates.
(if (< (+ month (* 12 (1- year))) 2)
(error "Months before January, 1 AD cannot be displayed"))
(setq displayed-month month
displayed-year year)
(erase-buffer)
(calendar-increment-month month year -1)
(dotimes (i 3)
(calendar-generate-month month year
(+ calendar-left-margin
(* calendar-month-width i)))
(calendar-increment-month month year 1)))
Here, (dotimes (i 3) ...) generate 3 months in a row.
So if you want to generate more than 3 months in more than 1 row, you must override calendar-generate function by yourself, same as #Luke said.