I'm doing a bit of programming here and there in Emacs Lisp, but I'm not entirely sure how to go about certain things.
I'm trying to insert a whole month of dates, each on a new line like the list below:
January
01/01/09 Mon:
02/01/09 Tue:
03/01/09 Wed:
etc
How would I go about doing that? I've found how to format dates, but I can't find how to loop over a certain range of dates (in this instance to loop round a whole month and print a date for each day in the month).
Has anyone got some pointers they could give me on how to get started?
The functions you want are 'encode-time, 'format-time-string, and 'decode-time.
For the proper documentation, either C-h f function-name or will give you the documentation for the function, or the general elisp info pages can be found here: C-h i m elisp RET m time conversion RET
Here's that snippet:
(defun my-insert-dates ()
"insert a bunch of dates"
(interactive)
(let* ((month 3)
(day 1)
(time (encode-time 1 1 0 day month 2009)))
(while (= (nth 4 (decode-time time)) month)
(insert (format-time-string "%D %a:\n" time))
(setq day (1+ day))
(setq time (encode-time 1 1 0 day month 2009)))))
I couldn't find how to determine the number of days in a given month (sure, you could hard-code it, but then you've got to deal with leap years). Luckily, 'encode-time does all the addition for you, so if you pass it the equivalent of "February 31", it'll return "March 3" (assuming 28 days).
I would have done something like this, if you don't mind using the calendar feature...
(require 'calendar)
(defun display-a-month (day month year)
(insert (format "%s\n" (calendar-date-string (list month day year))))
(if (< day 30)
(display-a-month (+ day 1) month year)))
You can find help using describe-function (M-x describe-function or C-h f as said before); M-x apropos will give you a list of functions related to something and even better people on irc.freenode.org / #emacs will answer all you questions.
btw, the question was "insert a whole month" not "insert first day of each month" :) depends if you read dd/mm/yyyy of mm/dd/yyyy
Slight variation on Trey's answer using dotimes:
(defun my-insert-dates ()
"insert the first day of each month"
(interactive)
(dotimes (mo 12)
(insert (format-time-string "%D %a:\n" (encode-time 1 1 0 1 (1+ mo) 2009)))))
Related
In the Emacs manual the following is furnished as an example of a special entry in the Emacs Diary:
&%%(diary-float 11 4 4) American Thanksgiving
The 11 specifies the month, the first 4 specifies the day of the week (Thursday) and the second 4 the 4th Thursday of the month.
One can use t to indicate all months of the year, but how would one specify all Thursdays of the month? I have tried t and it does not work.
For example, let's say that every October I have to perform a duty, but not every day, only every Thursday. How would I capture that using a diary-float?
It's not possible to do this with diary-float, but as described in Sexp Entries in the Emacs manual, you can use an arbitrary Lisp expression in the diary file. This seems to work:
%%(let ((dayname (calendar-day-of-week date))
(month (car date)))
(and (= month 10) (= dayname 4))) It's a Thursday in October
I regularly mark habits as DONE the day after the activity was done. The habits module automatically updates a bunch of dates in the metadata when I do this, but the date is always today. So then, I have to manually edit the SCHEDULED, LOGBOOK, and LAST_REPEAT states.
Is there a way to mark a habit as DONE for a day in the past? So instead of doing C-c C-t d (I have "d" set up as "DONE") I could get a prompt which asked me for a date.
I've wanted to do this for some time, too, and your question inspired me to finally figure it out.
There is a function called "org-todo-yesterday." By default, it's not mapped to any keys, but you could always call it with M-x org-todo-yesterday (or map it if you're using it a lot). For me, it breaks because it calls "third" which isn't a defined function in my install.
For a more generic function that prompts us for the date and marks things as done at that time, we can add this function (inspired by org-todo-yesterday) to our emacs init file. It will act as if you finished things at 23:59 on the target date, which is hopefully good enough.
(defun dk/org-todo-custom-date (&optional arg)
"Like org-todo-yesterday, but prompt the user for a date. The time
of change will be 23:59 on that day"
(interactive "P")
(let* ((hour (nth 2 (decode-time
(org-current-time))))
(daysback (- (date-to-day (current-time-string)) (org-time-string-to-absolute (org-read-date))))
(org-extend-today-until (+ 1 (* 24 (- daysback 1)) hour))
(org-use-effective-time t)) ; use the adjusted timestamp for logging
(if (eq major-mode 'org-agenda-mode)
(org-agenda-todo arg)
(org-todo arg))))
Will this work? This simply completes the habit and reschedule it for today
(defun org-todo-yesterday2 (&optional arg)
(interactive "P")
(org-todo-yesterday arg)
(org-schedule arg (format-time-string "%Y-%m-%d")
)
)
I am using Emacs and open calendar, now i would like to highlight weekend days with a light background color, i tried to google but have no solid solutions. anyone can help on this? thanks a lot!
Sorry I can't post pictures yet, hope i have put the question clearly.
Here you have some code that does that. You would need to change font-lock-doc-string-face to the face you want to use (or make a new one and configure it) if you don't like the one I used.
(defadvice calendar-generate-month
(after highlight-weekend-days (month year indent) activate)
"Highlight weekend days"
(dotimes (i 31)
(let ((date (list month (1+ i) year)))
(if (or (= (calendar-day-of-week date) 0)
(= (calendar-day-of-week date) 6))
(calendar-mark-visible-date date 'font-lock-doc-string-face)))))
Intro:
Based on the existing code for Emacs' diary-sunrise-sunset, I attempted to create two new functions diary-sunrise and diary-sunset.
My reasons for this are included below under the heading "XY-description".
I have code below which seems to work, except when I restart with a new Emacs. I can fix this by momentarily using the original built-in diary-sunrise-sunset. From then on, my functions perform beautifully.
In other words, I have to use the built-in %%(diary-sunrise-sunset) just a one time before my %%(diary-sunrise) and %%(diary-sunset) will work.
Question:
Can you help me fix my use of these functions so that I do not have to take the awkward step of first getting the built-in function called?
The lines of code that seem suspicious to me are the ones that go
;;;###diary-autoload
While I have some idea of the necessity of loading programs, I am not sure what's going on here, or if this is where the issue lies. (I've never seen that particular syntax.)
I have tried M-: (require 'solar) and M-: (require 'diary), but neither have worked (and just now calendar). I have tried putting my code both in my .emacs and in the built-in .../lisp/calendar/solar.el (and byte-recompiling), but neither have worked.
My functions:
(They are each slight modifications of solar-sunrise-sunset-string and diary-sunrise-sunset, which are both defined in .../lisp/calendar/solar.el).
Sunrise:
(defun solar-sunrise-string (date &optional nolocation)
"String of *local* time of sunrise and daylight on Gregorian DATE."
(let ((l (solar-sunrise-sunset date)))
(format
"%s (%s hours daylight)"
(if (car l)
(concat "Sunset " (apply 'solar-time-string (car l)))
"no sunset")
(nth 2 l)
)))
;; To be called from diary-list-sexp-entries, where DATE is bound.
;;;###diary-autoload
(defun diary-sunrise ()
"Local time of sunrise as a diary entry.
Accurate to a few seconds."
(or (and calendar-latitude calendar-longitude calendar-time-zone)
(solar-setup))
(solar-sunrise-string date))
Sunset:
(defun solar-sunset-string (date &optional nolocation)
"String of *local* time of sunset and daylight on Gregorian DATE."
(let ((l (solar-sunrise-sunset date)))
(format
"%s (%s hours daylight)"
(if (cadr l)
(concat "Sunset " (apply 'solar-time-string (cadr l)))
"no sunset")
(nth 2 l)
)))
;; To be called from diary-list-sexp-entries, where DATE is bound.
;;;###diary-autoload
(defun diary-sunset ()
"Local time of sunset as a diary entry.
Accurate to a few seconds."
(or (and calendar-latitude calendar-longitude calendar-time-zone)
(solar-setup))
(solar-sunset-string date))
XY description:
I am using Emacs' Org-mode, and just starting to use agenda views. I like the builtin diary-sunrise-sunset function, but wanted to make some minor tweaks to make it more to my liking.
Basically, Org-mode's agenda view will extract the first time it sees from the diary sexp %%(diary-sunrise-sunset), for instance
Sat, Apr 5, 2014
Sunrise 6:43am (PDT), sunset 7:42pm (PDT) at Springfield, OH (12:59 hours daylight)
and thus make an entry of
6:43am........ Sunrise (PDT), sunset 7:42pm (PDT) at Springfield, OH (12:59 hours daylight)
in the agenda view.
What I would like it to do is something more like,
6:43am........ Sunrise (PDT) (12:59 hours daylight)
8:00am........ ----------------
10:00am........ ----------------
12:00pm........ ----------------
2:00pm........ ----------------
4:00pm........ ----------------
5:51pm........ now - - - - - - - - - - - - - - - - - - - - - - - - -
6:00pm........ ----------------
7:42pm........ Sunset (PDT) (12:59 hours daylight)
Where the data is split into the two times, rather than all written only at the sunrise time.
Bonus:
a snippet so that C-c a d will give you a nice day agenda view:
(setq org-agenda-custom-commands
'(("d" "day's agenda"
agenda ""
(
(org-agenda-files '("/e/org/agendatest.org"))
(org-agenda-prefix-format "%t %s")
(org-agenda-span 'day)
(org-agenda-timegrid-use-ampm t)
)
)
))
In the last paragraph of my question (eighth paragraph?), I lied, (require 'solar) was the answer... I did not try it hard enough as it didn't respond to auto-completion.
The scenic route to the answer took me to these distractions:
Maintaining Emacs autoload files for user-installed elisp?
elisp - Where should I add autoload cookies in my Emacs Lisp package? Is there a definitive guide?
C-h i g (elisp) Autoload
a search through the lisp directory for any update-file-autoloads
I did some Edebugging wondering if anything I was using had an autoload cookie (not completely understanding it yet), but then noticed there was a (provide 'solar) at the end of solar.el, so then I figured (require 'solar) had to work. It did and that was that.
From the code in my question, I remove the autoload cookies (not sure if that's necessary), and add (require 'solar), and it works! Enjoy!
I have the following function definition:
(defun nth (n)
(format
(concat
"%d"
(if (memq n '(11 12 13)) "th"
(let ((last-digit (% n 10)))
(case last-digit
(1 "st")
(2 "nd")
(3 "rd")
(otherwise "th"))))) n))
and I'd like to be able to use it in format-time-string.
Normally, I would look at the source of the function, but this one is defined in the C source code. (I would presume this precludes hooking something onto it, but I stand to be corrected.)
How can I add another format specifier (say, %o) that will apply nth to the appropriate argument?
Desired usage:
(format-time-string "%A, %B %o, %T (%z)" (seconds-to-time 1250553600))
=> "Monday, August 17th, 20:00:00 (-0400)"
Here is what you want to do. Stefan and Drew already gave some important remarks (don't overwrite nth and look at the info-files of emacs-lisp/advising functions).
(defun ordinal (n)
"Special day of month format."
(format
(concat
"%d"
(if (memq n '(11 12 13)) "th"
(let ((last-digit (% n 10)))
(case last-digit
(1 "st")
(2 "nd")
(3 "rd")
(otherwise "th"))))) n))
(defadvice format-time-string (before ordinal activate)
"Add ordinal to %d."
(let ((day (nth 3 (decode-time (or time (current-time))))))
(setq format-string
(replace-regexp-in-string "%o"
(ordinal day)
format-string))))
Notes:
I did not handle the UNIVERSAL argument
The hack does not work when format-time-string is called from C (as you can read in the manual).
AFAIK you're out of luck: format-time-string does not offer any way to do that.
You might be able to work around this by using something like:
(let ((ti (seconds-to-time 1250553600)))
(format-time-string (concat "%A, %B " (my-nth (format-time-string "%d" ti)) ", %T (%z)") ti))
This said, I've always been told that "August 17th" is wrong: you're supposed to write "August 17" which is pronounced "August the seventheenth".
One more thing: nth is a predefined core function. Better not overwrite it with your own completely different definition.
To add to what Stefan said ("You're out of luck") --
format-time-string is a built-in, but you can advise built-ins too. However, since the kind of surgery you want to do would dig into the bowels of the definition (which you cannot do), you would need to in fact replace the definition of format-time-string in the defadvice, i.e., not use ad-do-it at all.
In other words, one way or the other (defun or defadvice) you would need to completely redefine the function, in Lisp. Which is about the same as saying "You're out of luck."