├── .github
└── workflows
│ ├── codecov.yml
│ ├── go.yml
│ └── scorecards.yml
├── .gitignore
├── CONTRIBUTING.md
├── Devel.md
├── LICENSE
├── Makefile
├── README.md
├── doc.go
├── examples
├── 01-2025.png
├── example01.png
├── example02.png
├── example03.png
├── example04.png
├── example05.png
├── example06.png
├── example07.png
├── example08.png
├── example09.png
├── example10.png
├── example11.png
├── example12.png
├── example13.png
├── example14.png
├── example15.png
├── example16.png
├── example17.png
├── example18.png
└── example19.png
├── fonts
├── FreeMonoBold.ttf
├── FreeSansBold.ttf
└── FreeSerifBold.ttf
├── gnufreefont-License.txt
├── go.mod
├── go.sum
├── gocal-default.nix
├── gocal.go
├── gocal_test.go
├── gocalendar.man
├── gocalendar
├── data
│ ├── Borel-Regular.ttf
│ ├── german.ics
│ ├── hybrid.xml
│ └── names.xml
├── gocalendar.go
├── pics
│ ├── cooper.jpg
│ ├── eddi.JPG
│ ├── golang-gopher.png
│ ├── mayflower.JPG
│ ├── taxi.JPG
│ └── wampanoag.JPG
└── sample.sh
├── golang-gopher.png
├── test-gocal.xml
└── util.go
/.github/workflows/codecov.yml:
--------------------------------------------------------------------------------
1 | name: Test and coverage
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v2
10 | with:
11 | fetch-depth: 2
12 | - uses: actions/setup-go@v2
13 | with:
14 | go-version: '1.22'
15 | - name: Run coverage
16 | run: go test -race -coverprofile=coverage.txt -covermode=atomic
17 | - name: Upload coverage to Codecov
18 | uses: codecov/codecov-action@v3
19 |
--------------------------------------------------------------------------------
/.github/workflows/go.yml:
--------------------------------------------------------------------------------
1 | name: Go
2 |
3 | on:
4 | push:
5 | branches: [ "master" ]
6 | pull_request:
7 | branches: [ "master" ]
8 |
9 | jobs:
10 |
11 | build:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v3
15 |
16 | - name: Set up Go
17 | uses: actions/setup-go@v3
18 | with:
19 | go-version: 1.18
20 |
21 | - name: Build
22 | run: go build -v ./...
23 |
24 | - name: Test
25 | run: go test -v ./...
26 |
--------------------------------------------------------------------------------
/.github/workflows/scorecards.yml:
--------------------------------------------------------------------------------
1 | name: Scorecards supply-chain security
2 | on:
3 | # Only the default branch is supported.
4 | branch_protection_rule:
5 | schedule:
6 | - cron: '26 17 * * 1'
7 | push:
8 | branches: [ "master" ]
9 |
10 | # Declare default permissions as read only.
11 | permissions: read-all
12 |
13 | jobs:
14 | analysis:
15 | name: Scorecards analysis
16 | runs-on: ubuntu-latest
17 | permissions:
18 | # Needed to upload the results to code-scanning dashboard.
19 | security-events: write
20 | # Used to receive a badge.
21 | id-token: write
22 | # Needs for private repositories.
23 | contents: read
24 | actions: read
25 |
26 | steps:
27 | - name: "Checkout code"
28 | uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846 # tag=v3.0.0
29 | with:
30 | persist-credentials: false
31 |
32 | - name: "Run analysis"
33 | uses: ossf/scorecard-action@865b4092859256271290c77adbd10a43f4779972 # tag=v2.0.3
34 | with:
35 | results_file: results.sarif
36 | results_format: sarif
37 | # (Optional) Read-only PAT token. Uncomment the `repo_token` line below if:
38 | # - you want to enable the Branch-Protection check on a *public* repository, or
39 | # - you are installing Scorecards on a *private* repository
40 | # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
41 | # repo_token: ${{ secrets.SCORECARD_READ_TOKEN }}
42 |
43 | # Publish the results for public repositories to enable scorecard badges. For more details, see
44 | # https://github.com/ossf/scorecard-action#publishing-results.
45 | # For private repositories, `publish_results` will automatically be set to `false`, regardless
46 | # of the value entered here.
47 | publish_results: true
48 |
49 | # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
50 | # format to the repository Actions tab.
51 | - name: "Upload artifact"
52 | uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # tag=v3.0.0
53 | with:
54 | name: SARIF file
55 | path: results.sarif
56 | retention-days: 5
57 |
58 | # Upload the results to GitHub's code scanning dashboard.
59 | - name: "Upload to code-scanning"
60 | uses: github/codeql-action/upload-sarif@5f532563584d71fdef14ee64d17bafb34f751ce5 # tag=v1.0.26
61 | with:
62 | sarif_file: results.sarif
63 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | gocal.exe
2 | test-output/*
3 | output.pdf
4 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | Note: This CONTRIBUTING.md was generated using https://generator.contributing.md/
4 |
5 | # Contributing to Gocal
6 |
7 | First off, thanks for taking the time to contribute! ❤️
8 |
9 | All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉
10 |
11 | > And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about:
12 | > - Star the project
13 | > - Tweet about it
14 | > - Refer this project in your project's readme
15 | > - Mention the project at local meetups and tell your friends/colleagues
16 |
17 |
18 | ## Table of Contents
19 |
20 | - [I Have a Question](#i-have-a-question)
21 | - [I Want To Contribute](#i-want-to-contribute)
22 | - [Reporting Bugs](#reporting-bugs)
23 | - [Suggesting Enhancements](#suggesting-enhancements)
24 | - [Your First Code Contribution](#your-first-code-contribution)
25 | - [Improving The Documentation](#improving-the-documentation)
26 | - [Styleguides](#styleguides)
27 | - [Commit Messages](#commit-messages)
28 | - [Join The Project Team](#join-the-project-team)
29 |
30 |
31 |
32 | ## I Have a Question
33 |
34 | > If you want to ask a question, we assume that you have read the available [Documentation](https://github.com/StefanSchroeder/Gocal).
35 |
36 | Before you ask a question, it is best to search for existing [Issues](https://github.com/StefanSchroeder/Gocal/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.
37 |
38 | If you then still feel the need to ask a question and need clarification, we recommend the following:
39 |
40 | - Open an [Issue](https://github.com/StefanSchroeder/Gocal/issues/new).
41 | - Provide as much context as you can about what you're running into.
42 | - Provide project and platform versions (nodejs, npm, etc), depending on what seems relevant.
43 |
44 | We will then take care of the issue as soon as possible.
45 |
46 |
60 |
61 | ## I Want To Contribute
62 |
63 | > ### Legal Notice
64 | > When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project license.
65 |
66 | ### Reporting Bugs
67 |
68 |
69 | #### Before Submitting a Bug Report
70 |
71 | A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.
72 |
73 | - Make sure that you are using the latest version.
74 | - Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](https://github.com/StefanSchroeder/Gocal). If you are looking for support, you might want to check [this section](#i-have-a-question)).
75 | - To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/StefanSchroeder/Gocalissues?q=label%3Abug).
76 | - Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.
77 | - Collect information about the bug:
78 | - Stack trace (Traceback)
79 | - OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
80 | - Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
81 | - Possibly your input and the output
82 | - Can you reliably reproduce the issue? And can you also reproduce it with older versions?
83 |
84 |
85 | #### How Do I Submit a Good Bug Report?
86 |
87 | > You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead sensitive bugs must be sent by email to <>.
88 |
89 |
90 | We use GitHub issues to track bugs and errors. If you run into an issue with the project:
91 |
92 | - Open an [Issue](https://github.com/StefanSchroeder/Gocal/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
93 | - Explain the behavior you would expect and the actual behavior.
94 | - Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
95 | - Provide the information you collected in the previous section.
96 |
97 | Once it's filed:
98 |
99 | - The project team will label the issue accordingly.
100 | - A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as `needs-repro`. Bugs with the `needs-repro` tag will not be addressed until they are reproduced.
101 | - If the team is able to reproduce the issue, it will be marked `needs-fix`, as well as possibly other tags (such as `critical`), and the issue will be left to be [implemented by someone](#your-first-code-contribution).
102 |
103 |
104 |
105 |
106 | ### Suggesting Enhancements
107 |
108 | This section guides you through submitting an enhancement suggestion for Gocal, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.
109 |
110 |
111 | #### Before Submitting an Enhancement
112 |
113 | - Make sure that you are using the latest version.
114 | - Read the [documentation](https://github.com/StefanSchroeder/Gocal) carefully and find out if the functionality is already covered, maybe by an individual configuration.
115 | - Perform a [search](https://github.com/StefanSchroeder/Gocal/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
116 | - Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
117 |
118 |
119 | #### How Do I Submit a Good Enhancement Suggestion?
120 |
121 | Enhancement suggestions are tracked as [GitHub issues](https://github.com/StefanSchroeder/Gocal/issues).
122 |
123 | - Use a **clear and descriptive title** for the issue to identify the suggestion.
124 | - Provide a **step-by-step description of the suggested enhancement** in as many details as possible.
125 | - **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you.
126 | - You may want to **include screenshots and animated GIFs** which help you demonstrate the steps or point out the part which the suggestion is related to. You can use [this tool](https://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux.
127 | - **Explain why this enhancement would be useful** to most Gocal users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
128 |
129 |
130 |
131 | ### Your First Code Contribution
132 |
136 |
137 | ### Improving The Documentation
138 |
142 |
143 | ## Styleguides
144 | ### Commit Messages
145 |
148 |
149 | ## Join The Project Team
150 |
151 |
152 |
153 | ## Attribution
154 | This guide is based on the **contributing-gen**. [Make your own](https://github.com/bttger/contributing-gen)!
155 |
--------------------------------------------------------------------------------
/Devel.md:
--------------------------------------------------------------------------------
1 | # Developer notes
2 |
3 | This application is primarily developed under Linux, but will run
4 | under Windows. Please let me know if it also works on other
5 | platforms.
6 |
7 | The program grew using the good old Copy and Paste method. It is
8 | not designed to be a lighthouse of great architecture, but to
9 | solve a problem.
10 |
11 | The man-page requires the program go-md2man and sed/awk.
12 | The man-page is essentially a patched version of the README.md.
13 |
14 | https://github.com/cpuguy83/go-md2man.git
15 |
16 | Because it's not assumed that the program is available usually,
17 | the generated man-page is part of the release.
18 |
19 | I am going to improve the openssf-scorecard rating and the
20 | code-coverage of the tests.
21 |
22 | Also, I might try to get the tool into NixOS.
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2014 Stefan Schroeder
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # Run 'make' to create some test PDFs.
3 | # This Makefile does not build the binaries.
4 | # Use the go tools for building.
5 | #
6 | all:
7 | mkdir -p test-output
8 | go run gocalendar/gocalendar.go -spread 1 -yearA -o test-output/test-example_ao1.pdf -lang de_DE 2021
9 | go run gocalendar/gocalendar.go -spread 2 -yearA -o test-output/test-example_ao2.pdf -lang de_DE 2021
10 | go run gocalendar/gocalendar.go -spread 3 -yearA -o test-output/test-example_ao3.pdf -lang de_DE 2021
11 | go run gocalendar/gocalendar.go -spread 4 -yearA -o test-output/test-example_ao4.pdf -lang de_DE 2021
12 | go run gocalendar/gocalendar.go -spread 6 -yearA -o test-output/test-example_ao6.pdf -lang de_DE 2021
13 | go run gocalendar/gocalendar.go -spread 12 -yearA -o test-output/test-example_ao12.pdf -lang de_DE 2021
14 | go run gocalendar/gocalendar.go -spread 1 -yearB -o test-output/test-example_bo1.pdf -lang de_DE 2021
15 | go run gocalendar/gocalendar.go -spread 2 -yearB -o test-output/test-example_bo2.pdf -lang de_DE 2021
16 | go run gocalendar/gocalendar.go -spread 3 -yearB -o test-output/test-example_bo3.pdf -lang de_DE 2021
17 | go run gocalendar/gocalendar.go -spread 4 -yearB -o test-output/test-example_bo4.pdf -lang de_DE 2021
18 | go run gocalendar/gocalendar.go -spread 6 -yearB -o test-output/test-example_bo6.pdf -lang de_DE 2021
19 | go run gocalendar/gocalendar.go -spread 12 -yearB -o test-output/test-example_bo12.pdf -lang de_DE 2021
20 |
21 | man:
22 | cat README.md | \
23 | sed -n '8,9999p' | \
24 | awk ' /^#/ { print toupper($$0)}; !/^#/{ print $$0} ' > gocalendar_temp.md
25 | go-md2man -in gocalendar_temp.md -out gocalendar.man
26 | rm gocalendar_temp.md
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | [](https://opensource.org/licenses/MIT)
4 | [](https://github.com/StefanSchroeder/Gocal/actions/workflows/go.yml)
5 | [](https://godoc.org/github.com/StefanSchroeder/Gocal)
6 | [](https://goreportcard.com/report/github.com/StefanSchroeder/Gocal)
7 | [](https://api.securityscorecards.dev/projects/github.com/StefanSchroeder/Gocal)
8 | [](https://codecov.io/github/StefanSchroeder/Gocal)
9 |
10 | # "Gocal and Gocalendar"
11 |
12 | # Name
13 | Gocal is a simple clone of pcal.
14 |
15 | # Synopsis
16 |
17 | gocalendar 2024 # Create a 12-page calendar for YEAR, e.g. 2024
18 |
19 | gocalendar 5 2025 # Create a 1-page calendar for the MONTH in YEAR, e.g. 5 2025
20 |
21 | gocalendar 5 7 2026 # Create a sequence from BEGIN to END in YEAR
22 |
23 | # Description
24 |
25 | The project includes a cli tool and a library to create
26 | monthly calendars in PDF. By default it creates a
27 | 12-page PDF with one month per page for the current year.
28 | The library is called gocal, while the standalone tool is named gocalendar.
29 |
30 | Gocalendar can be built with `go build` in the gocalendar folder.
31 |
32 | There is a year mode that shows the entire year on one page.
33 | Have a look at the examples to get an idea of Gocal's capabilities.
34 |
35 | Gocal was built because of pcal's lack of support for UTF-8 and because I feel
36 | that Postscript is obsolete.
37 |
38 |
39 | # Features
40 |
41 | * PDF generation
42 | * Week number on every Monday
43 | * Day of year
44 | * Moon phases
45 | * Events in XML configuration file
46 | * Several languages
47 | * Wallpaper option
48 | * Photo calendar option (from single image or directory)
49 | * Page orientation and paper size option
50 | * Font selection
51 | * Year calendar (two layouts)
52 | * Import of ICS files (local file or URL)
53 |
54 |
55 | The main design goal of gocal is simplicity. While it is absolutely possible to create
56 | an application where every single stroke is configurable, I believe that most
57 | of you are too busy to play around with lots of options and want a pleasant
58 | calendar out-of-the-box. That's what gocal provides.
59 |
60 | The power of gocal is based on the cool libraries that it includes. This
61 | implies that several of the options are actually options of the libraries, e.g.
62 | the paper format (gofpdf) or the supported languages (goodsign/monday).
63 |
64 | It is suggested to hide some of the optional fields or the cells will look
65 | crowded.
66 |
67 |
68 | # Build
69 |
70 | Run
71 |
72 | go install github.com/StefanSchroeder/Gocal/gocalendar@latest
73 |
74 | This will install the *gocalendar* executable in your go-bin folder.
75 |
76 | Or the long haul:
77 |
78 | Run
79 |
80 | go get github.com/StefanSchroeder/Gocal
81 |
82 | Gocal has a quite a few dependencies that go should resolve automatically.
83 |
84 | To build the standalone tool, change into the gocalendar directory and run
85 |
86 | go build
87 |
88 | You create a bunch of sample files (and in passing test gocal) by running
89 |
90 | go test
91 |
92 |
93 | # Example library use
94 |
95 | package main
96 | import (
97 | "github.com/StefanSchroeder/gocal"
98 | )
99 | func main() {
100 | g := gocal.New(1,12,2010)
101 | g.CreateCalendar("test-example01.pdf")
102 | }
103 |
104 | # License
105 |
106 | The license is in the LICENSE file. (It's MIT.)
107 |
108 | # API-documentation
109 |
110 | For the API documentation of gocal the library [visit the auto-generated docs on
111 | godoc.org](https://pkg.go.dev/github.com/StefanSchroeder/Gocal).
112 |
113 | # Options of gocalendar
114 |
115 | ### Help
116 |
117 | -h Help: Summarizes the options.
118 |
119 | ### Footer
120 |
121 | -f="Gocal": Footer note
122 |
123 | Change the string at the bottom of the page. To disable the footer, simply set
124 | it to the empty string.
125 |
126 | ### Margin note
127 |
128 | -margin="Some string": A margin note on the right margin.
129 |
130 | A note that that can easily be read when flipping through pages.
131 | E.g. when you have a lot of calendars for staff in a binder.
132 |
133 | ### Font
134 |
135 | -font="": font
136 |
137 | -font serif (Times lookalike)
138 | -font mono (Courier lookalike)
139 | -font sans (Arial lookalike)
140 | -font path/to/font.ttf (your favorite font)
141 |
142 | Set the font. Only truetype fonts are supported. Look into c:\Windows\Fonts on
143 | Windows and /usr/share/fonts to see what fonts you have. Gocal comes with three
144 | fonts built-in: The Gnu FreeMonoBold, FreeSerifBold and FreeSansBold. They look
145 | pretty similar to (in that order) Courier, Times and Arial and should meet all
146 | your standard font needs. These fonts are licensed under the Gnu FreeFont
147 | License which accompanies this README.txt. Read more about them at
148 | https://www.gnu.org/software/freefont. Auxiliary files are created in a
149 | temporary directory.
150 |
151 | The Borel-font in the sample directory is licensed under the OPL
152 | and contained here only for testing purposes.
153 | It was downloaded from https://fontesk.com/borel-font/.
154 |
155 | In addition you can provide your own TTF on the commandline if you prefer something fancy.
156 |
157 | ### Font size
158 |
159 | Font sizes relative to the default size can be set with
160 |
161 | -fontscale floatingpoint number
162 |
163 | The default is 1.0 and typically you shouldn't need to change the font size
164 | drastically. But since weekday names in some languages might be a lot longer
165 | than in other languages, ugly collisions may occur. To avoid that you can
166 | rescale the fonts a little by setting -fontscale to 0.9. There is a shortcut
167 | to reduce the fontsizes globally to 75% of the default size to gain more room
168 | for manual notes.
169 |
170 | -small
171 |
172 |
173 | ### Language
174 |
175 | -lang="": Language
176 |
177 | Gocal reads the LANG environment variable. If it matches one of
178 |
179 | "ca_ES" "da_DK" "de_DE" "en_GB" "en_US" "es_ES" "fi_FI" "fr_CA" "fr_FR"
180 | "fr_GF" "fr_GP" "fr_LU" "fr_MQ" "fr_RE" "hu_HU" "id_ID" "it_IT" "nb_NO" "nl_BE"
181 | "nl_NL" "nn_NO" "pt_BR" "pt_PT" "sv_SE" "uz_UZ"
182 |
183 | the library goodsign/monday is used to translate the weekday names and month
184 | names. Although this library supports a few other languages, I found that some
185 | of the languages do not work with the fonts I tried. The language from the
186 | environment can be overridden with this parameter. If your LANG is not
187 | recognized, we default to en_US.
188 |
189 | ### Hiding stuff
190 |
191 | -nodoy: Hide day of year
192 |
193 | -nomoon: Hide moon phases
194 |
195 | -noweek: Hide week number
196 |
197 | The week number according to ISO-8601 is added on every Monday by default.
198 |
199 | -noother: Hide neighbormonth days
200 |
201 | This option hides the leading and trailing days of the neighbor months.
202 | By default these days are printed in light grey.
203 |
204 | -plain This will hide everything that can be hidden (but not neighbormonth days).
205 |
206 | ### Output
207 |
208 | -o="output.pdf": Output filename
209 |
210 | ### Paper orientation
211 |
212 | -p="L": Orientation (L)andscape/(P)ortrait
213 |
214 | Typically you want landscape for calendars without image and portrait for calendars with image.
215 |
216 | ### Paper format
217 |
218 | -paper="A4": Paper format (A3 A4 A5 Letter Legal)
219 |
220 |
221 | ### Graying out
222 |
223 | -fill configure filled grid
224 |
225 | Can be any combination of:
226 |
227 | X even columns filled gray
228 |
229 | x odd columns filled gray
230 |
231 | Y even rows filled gray
232 |
233 | y odd rows filled gray
234 |
235 | S Sundays filled gray
236 |
237 | s Saturdays filled gray
238 |
239 | 1 Monday
240 |
241 | 2 Tuesday
242 |
243 | 3 Wednesday
244 |
245 | 4 Thursday
246 |
247 | 5 Friday
248 |
249 | 6 Saturday
250 |
251 | 7 Sunday
252 |
253 | Example:
254 |
255 | -fill "x3Y"
256 |
257 | The gray boxes are not transparent; therefore it doesn't make a lot
258 | of sense to combine gray boxes with a wallpaper image.
259 |
260 |
261 | ### Photo / Photos / Wallpaper
262 |
263 | -photo=filename: Show single photo (single image in PNG JPG GIF)
264 |
265 | This option will add this image to every month.
266 | The filename can be a URL, qualified with http:// and it must have a valid image extension.
267 |
268 | -photos=directory: Show multiple photos (directory with PNG JPG GIF)
269 |
270 | e.g. gocal -photos images/
271 |
272 | This option will add the twelve first files as images to the twelve month. If
273 | less than twelve files are found, the sequence will re-start after the last
274 | image. This will not work if there are non-image files in the directory (among
275 | the first twelve). The directory option does NOT support URLs.
276 |
277 | -wall=filename: Show wallpaper PNG JPG GIF
278 |
279 | e.g. gocal -wall gopher.png
280 |
281 | This option will add this image to every month as a background. You should only
282 | use images with a bright tone so that you do not obstruct the usefulness of the
283 | calendar. The filename can be a URL, and must start with http:// and must have
284 | a valid image extension.
285 |
286 |
287 | ### Year calendar
288 |
289 | -yearA
290 |
291 | -yearB
292 |
293 | Two different layouts are available. One with the months on the top and the
294 | days on the left and vice versa. Obviously there is less space for the
295 | individual day in this mode. Still, many of the options are available here.
296 |
297 | -spread NUMBER
298 |
299 | In the year calendars, the entire calendar is put on one page. Using the
300 | spread option, you can spread the year across NUMBER pages. Valid values are
301 | 1 (default), 2, 3, 4, 6 and 12. Using 12 is essentially the same as not using the
302 | year mode, because it will put every month on its own page.
303 |
304 | Example:
305 |
306 | -yearB -spread 4
307 |
308 | This will put three months on each page.
309 |
310 |
311 | # Event File
312 |
313 | This is a sample file event configuration file.
314 | Image can be a URL, which must start with http://
315 |
316 | Load the file with
317 |
318 | `-config myfile.xml`
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 | Please note the cool Anglo-Saxon/Scandinavian letters, thanks to UTF-8 support.
339 |
340 | This is a sample of the configuration file for gocal. It has all the supported
341 | features. date is in MONTH/DAY format. The text may contain a literal \n
342 | newline. For the month a * is permitted and it obviously means 'every month'.
343 | You can use a leading newline symbol to make the text wrap to the next line in
344 | case of overlap. THe optional image tag will put an image into the cell.
345 |
346 | For the day an English Weekday name is permitted. It means: Every
347 | matching weekday.
348 |
349 | I was considering to allow to configure all the options from the command line
350 | also as parameters in the XML, but I think it's not really that important.
351 |
352 | The image can also be URL, but keep in mind, that every image will be
353 | downloaded every time, because the files are downloaded to a temporary folder
354 | which is deleted after gocalendar is done.
355 |
356 | # ICS iCalendar files
357 |
358 | Using
359 |
360 | -ics filename or URL
361 |
362 | you can provide one or more ICS calendar objects. The events in
363 | the calendar will be added on matching dates.
364 |
365 | Timezones are ignored. There is still no automatic linebreaking
366 | and no prevention of overlap with other configuration event
367 | entries.
368 |
369 | From the ICS file, the *SUMMARY* attribute is added as text to
370 | the calendar.
371 |
372 | Example:
373 |
374 | gocalendar -ics http://www.google.com/calendar/ical/de.german%23holiday%40group.v.calendar.google.com/public/basic.ics
375 | # Add German holidays to your calendar (because why wouldn't you).
376 |
377 | Example:
378 |
379 | gocalendar -ics my.ics
380 | # Add your own local ICS file.
381 |
382 | # Examples
383 |
384 | There is more than one way to create some example calendars.
385 |
386 | You can use `go test` to validate that the library works
387 | or you can run `make` after compilation to check that the standalone
388 | tool works. Both procedures provide ample suggestions what you can do.
389 |
390 | The blue frames are not part of the Gocal output, but have been
391 | added for these screenshots.
392 |
393 | 
394 |
395 | gocalendar -o example01.pdf -p P -photos pics 1 2026
396 |
397 | 
398 |
399 | gocalendar -o example02.pdf -lang fr_FR -font sans 2027
400 |
401 | 
402 |
403 | gocalendar -o example03.pdf -wall golang-gopher.png -lang de_DE -font data/Borel-Regular.ttf 2028
404 |
405 | 
406 |
407 | gocalendar -o example04.pdf -lang de_DE -font mono 2 2029
408 |
409 | 
410 |
411 | gocalendar -o example05.pdf -lang nl_NL -plain 3 2030
412 |
413 | 
414 |
415 | gocalendar -o example06.pdf -font data/Borel-Regular.ttf -lang en_US 4 2031
416 |
417 | 
418 |
419 | gocalendar -o example07.pdf -p P -lang fr_FR -photo pics\taxi.JPG 4 2032
420 |
421 | 
422 |
423 | gocalendar -o example08.pdf -lang fr_FR -photo golang-gopher.png 4 2033
424 |
425 | 
426 |
427 | gocalendar -o example09.pdf -lang fi_FI -font serif -p L 4 2034
428 |
429 | 
430 |
431 | gocalendar -o example10.pdf -lang fi_FI -font serif -p L 12 2035
432 |
433 | 
434 |
435 | gocalendar -o example11.pdf -lang de_DE -font sans -p L 6 9 2036
436 |
437 | 
438 |
439 | gocalendar -o example12.pdf -p P -photo http://golang.org/doc/gopher/frontpage.png 7 2037
440 |
441 | 
442 |
443 | gocalendar -o example13.pdf -font sans -noother 7 2038
444 |
445 | 
446 |
447 | gocalendar -o example14.pdf -small 2 2039
448 |
449 | 
450 |
451 | gocalendar -o example15.pdf -yearA 2040
452 |
453 | 
454 |
455 | gocalendar -o example16.pdf -yearB 2041
456 |
457 | 
458 |
459 | gocalendar -o example17.pdf -yearA -fill "c" 2042
460 |
461 | 
462 |
463 | gocalendar -o example18.pdf -yearB -fill "sS" 2043
464 |
465 | 
466 |
467 | gocalendar -o example19.pdf -ics data/german.ics 12 2023
468 |
469 |
470 | # Roadmap
471 |
472 | This is a mature application that I use regularly and that meets all
473 | my needs. If you are looking for a fancy option, let me know by
474 | writing an issue. I will consider adding it.
475 |
476 | # Known bugs
477 |
478 | * When you have multiple events on the same date, they are overlapping. I
479 | don't intend to fix that. Use the Newline to arrange your stuff.
480 | * Not all text will fit into the cells with some settings, because the font size is
481 | not adapted dynamically to the paper format. It's a feature, not a bug.
482 | * When using the A5 paper size, the last row of a page wraps to the next page.
483 | * Some warnings in libraries might irritate the user.
484 | * The dates and months are not validated. Nothing prevents you from trying to
485 | generate a calendar for "13 2014", which will panic.
486 |
487 |
488 | # Acknowledgments
489 |
490 | I'd like to thank the developers who wrote the great libraries that **gocal** is
491 | relying on, especially Sonia Keys and Kurt Jung and Йордан Пулов.
492 |
493 | # Copyright
494 |
495 | (C) Copyright Stefan Schröder
496 |
497 |
--------------------------------------------------------------------------------
/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Stefan Schroeder
3 | *
4 | * Use of this source code is governed by a BSD-style
5 | * license that can be found in the LICENSE file
6 | */
7 |
8 | /*
9 | Package gocal implements a PDF calendar generator. It consists of a
10 | library gocal and a standalone tool gocalendar.
11 |
12 | * Inspired by pcal
13 |
14 | * Simplicity: Create a nice calendar with minimum effort.
15 |
16 | * Week number
17 |
18 | * Moonphase
19 |
20 | * Add events from configuration file
21 |
22 | * Set papersize
23 |
24 | * Choose fonts (limited)
25 |
26 | * Several languages
27 |
28 | * Day of year
29 |
30 | * Background image
31 |
32 | * Photo calendar
33 |
34 | * More
35 |
36 | For build instructions, test instructions, examples, see
37 | README.md.
38 |
39 | EXAMPLE
40 |
41 | package main
42 | import (
43 | "github.com/StefanSchroeder/Gocal"
44 | )
45 | func main() {
46 | g := gocal.New(1,12,2010)
47 | g.CreateCalendar("test-example01.pdf")
48 | }
49 | */
50 | package gocal
51 |
--------------------------------------------------------------------------------
/examples/01-2025.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/01-2025.png
--------------------------------------------------------------------------------
/examples/example01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example01.png
--------------------------------------------------------------------------------
/examples/example02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example02.png
--------------------------------------------------------------------------------
/examples/example03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example03.png
--------------------------------------------------------------------------------
/examples/example04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example04.png
--------------------------------------------------------------------------------
/examples/example05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example05.png
--------------------------------------------------------------------------------
/examples/example06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example06.png
--------------------------------------------------------------------------------
/examples/example07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example07.png
--------------------------------------------------------------------------------
/examples/example08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example08.png
--------------------------------------------------------------------------------
/examples/example09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example09.png
--------------------------------------------------------------------------------
/examples/example10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example10.png
--------------------------------------------------------------------------------
/examples/example11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example11.png
--------------------------------------------------------------------------------
/examples/example12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example12.png
--------------------------------------------------------------------------------
/examples/example13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example13.png
--------------------------------------------------------------------------------
/examples/example14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example14.png
--------------------------------------------------------------------------------
/examples/example15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example15.png
--------------------------------------------------------------------------------
/examples/example16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example16.png
--------------------------------------------------------------------------------
/examples/example17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example17.png
--------------------------------------------------------------------------------
/examples/example18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example18.png
--------------------------------------------------------------------------------
/examples/example19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/examples/example19.png
--------------------------------------------------------------------------------
/fonts/FreeMonoBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/fonts/FreeMonoBold.ttf
--------------------------------------------------------------------------------
/fonts/FreeSansBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/fonts/FreeSansBold.ttf
--------------------------------------------------------------------------------
/fonts/FreeSerifBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/fonts/FreeSerifBold.ttf
--------------------------------------------------------------------------------
/gnufreefont-License.txt:
--------------------------------------------------------------------------------
1 | GNU FreeFont License
2 |
3 | Free UCS scalable fonts is free software; you can redistribute it and/or
4 | modify it under the terms of the GNU General Public License as published by
5 | the Free Software Foundation; either version 3 of the License, or (at your
6 | option) any later version.
7 |
8 | The fonts are distributed in the hope that they will be useful, but WITHOUT
9 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11 |
12 | You should have received a copy of the GNU General Public License along with
13 | this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
14 | Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 |
16 | As a special exception, if you create a document which uses this font, and
17 | embed this font or unaltered portions of this font into the document, this
18 | font does not by itself cause the resulting document to be covered by the GNU
19 | General Public License. This exception does not however invalidate any other
20 | reasons why the document might be covered by the GNU General Public License.
21 | If you modify this font, you may extend this exception to your version of the
22 | font, but you are not obligated to do so. If you do not wish to do so, delete
23 | this exception statement from your version.
24 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/StefanSchroeder/Gocal
2 |
3 | go 1.16
4 |
5 | require (
6 | github.com/PuloV/ics-golang v0.0.0-20190808201353-a3394d3bcade
7 | github.com/channelmeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61 // indirect
8 | github.com/goodsign/monday v1.0.1
9 | github.com/jung-kurt/gofpdf v1.16.2
10 | github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c
11 | github.com/soniakeys/meeus/v3 v3.0.1
12 | )
13 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/PuloV/ics-golang v0.0.0-20190808201353-a3394d3bcade h1:odEkSCl2gLWPtvraEdCyBZbeYyMMTysWPLMurnB8sUY=
2 | github.com/PuloV/ics-golang v0.0.0-20190808201353-a3394d3bcade/go.mod h1:f1P3hjG+t54/IrnXMnnw+gRmFCDR/ryj9xSQ7MPMkQw=
3 | github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
4 | github.com/channelmeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61 h1:o64h9XF42kVEUuhuer2ehqrlX8rZmvQSU0+Vpj1rF6Q=
5 | github.com/channelmeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61/go.mod h1:Rp8e0DCtEKwXFOC6JPJQVTz8tuGoGvw6Xfexggh/ed0=
6 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
7 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
8 | github.com/goodsign/monday v1.0.0 h1:Yyk/s/WgudMbAJN6UWSU5xAs8jtNewfqtVblAlw0yoc=
9 | github.com/goodsign/monday v1.0.0/go.mod h1:r4T4breXpoFwspQNM+u2sLxJb2zyTaxVGqUfTBjWOu8=
10 | github.com/goodsign/monday v1.0.1 h1:yJogH0uQNn4blHjoC3ESbdV0P1OhDtGYdd6x0w7QZBo=
11 | github.com/goodsign/monday v1.0.1/go.mod h1:r4T4breXpoFwspQNM+u2sLxJb2zyTaxVGqUfTBjWOu8=
12 | github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
13 | github.com/jung-kurt/gofpdf v1.16.2 h1:jgbatWHfRlPYiK85qgevsZTHviWXKwB1TTiKdz5PtRc=
14 | github.com/jung-kurt/gofpdf v1.16.2/go.mod h1:1hl7y57EsiPAkLbOwzpzqgx1A30nQCk/YmFV8S2vmK0=
15 | github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c h1:P6XGcuPTigoHf4TSu+3D/7QOQ1MbL6alNwrGhcW7sKw=
16 | github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c/go.mod h1:YnNlZP7l4MhyGQ4CBRwv6ohZTPrUJJZtEv4ZgADkbs4=
17 | github.com/phpdave11/gofpdi v1.0.7/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
18 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
19 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
20 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
21 | github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
22 | github.com/soniakeys/meeus/v3 v3.0.1 h1:inZIhWUeyumGoQ//CCZMI4qR2vPKCS6LbVPca2mDvqE=
23 | github.com/soniakeys/meeus/v3 v3.0.1/go.mod h1:G1tkqa+QcOyErSe7WqN0OnzVeLrvq9bQBoNb1IG+3n8=
24 | github.com/soniakeys/sexagesimal v1.0.0 h1:p4OW7ID1naq0+k0Sn/gvuS2hRgmEcuJrZeyyntOGLvU=
25 | github.com/soniakeys/sexagesimal v1.0.0/go.mod h1:/7psACvkUx/IZ1XX3HDdBci1Lz1ZObcjLX2MVVKI3rM=
26 | github.com/soniakeys/unit v1.0.0 h1:UMIgu6dxDQaK6tYaQV6dJn5oovB6035KRxCS0O7Jiec=
27 | github.com/soniakeys/unit v1.0.0/go.mod h1:z93o2tO/hJA2+Wr1Fozkt3jK4LyDwTfRCjyRFLAa4zk=
28 | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
29 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
30 | golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
31 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
32 |
--------------------------------------------------------------------------------
/gocal-default.nix:
--------------------------------------------------------------------------------
1 | { buildGoModule
2 | , fetchFromGitHub
3 | , lib
4 | }:
5 | buildGoModule rec {
6 | pname = "gocal";
7 | version = "0.9.0";
8 |
9 | src = fetchFromGitHub {
10 | owner = "StefanSchroeder";
11 | repo = "Gocal";
12 | rev = "v${version}";
13 | sha256 = "sha256-hTAZhpVfQSgXwPY6K9mDmJFdQcBRRhvW8TnntjrZrrE=";
14 |
15 | };
16 | vendorSha256 = "sha256-pNt7goaWR6gdf25t/SqwRQ+MYNdqOaUhRLKriAr2ocE=";
17 | meta = with lib; {
18 | description = "Create PDF calendars";
19 | homepage = "https://github.com/StefanSchroeder/Gocal";
20 | license = licenses.mit;
21 | maintainers = with maintainers; [ stefan ];
22 | mainProgram = "gocalendar";
23 | };
24 | }
25 |
--------------------------------------------------------------------------------
/gocal.go:
--------------------------------------------------------------------------------
1 | package gocal
2 |
3 | // Use of this source code is governed by a BSD-style
4 | // license that can be found in the LICENSE file
5 |
6 | /*
7 | This is gocal a tool to generate calendars in PDF for printing.
8 |
9 | https://github.com/StefanSchroeder/Gocal
10 | Copyright (c) 2014 Stefan Schroeder, NY, 2014-03-10
11 |
12 | */
13 |
14 | import (
15 | "fmt"
16 | "github.com/jung-kurt/gofpdf"
17 | "github.com/soniakeys/meeus/v3/julian"
18 | "os"
19 | "path/filepath"
20 | "strings"
21 | "time"
22 | )
23 |
24 | const (
25 | // LINES has to cover the number of weeks in one month.
26 | LINES = 6
27 | // COLUMNS equals the number of days in a week.
28 | COLUMNS = 7
29 | // MARGIN is the padding around the calendar on the page.
30 | MARGIN = 10.0 // MM
31 | // CELLMARGIN is the padding in the cell.
32 | CELLMARGIN = 1.0
33 |
34 | // DARKGREY is the intensity of grey in cell backgrounds.
35 | DARKGREY = 150
36 | // LIGHTGREY is the intensity of grey in neighbor month days.
37 | LIGHTGREY = 170
38 | // BLACK is black.
39 | BLACK = 0
40 |
41 | // MOONSIZE is the size of the moon icon.
42 | MOONSIZE = 4.0
43 |
44 | // Font sizes
45 | EVENTFONTSIZE = 10.0
46 | HEADERFONTSIZE = 32.0
47 | WEEKFONTSIZE = 12.0
48 | WEEKDAYFONTSIZE = 16.0
49 | DOYFONTSIZE = 12.0
50 | MONTHDAYFONTSIZE = 32.0
51 | FOOTERFONTSIZE = 12.0
52 | )
53 |
54 | var testedLanguage = map[string]bool{
55 | "en_US": true, // English (United States)
56 | "en_GB": true, // English (United Kingdom)
57 | "da_DK": true, // Danish (Denmark)
58 | "nl_BE": true, // Dutch (Belgium)
59 | "nl_NL": true, // Dutch (Netherlands)
60 | "fi_FI": true, // Finnish (Finland)
61 | "fr_FR": true, // French (France)
62 | "fr_CA": true, // French (Canada)
63 | "de_DE": true, // German (Germany)
64 | "hu_HU": true, // Hungarian (Hungary)
65 | "it_IT": true, // Italian (Italy)
66 | "nn_NO": true, // Norwegian Nynorsk (Norway)
67 | "nb_NO": true, // Norwegian Bokmål (Norway)
68 | "pl_PL": false, // Polish (Poland)
69 | "pt_PT": true, // Portuguese (Portugal)
70 | "pt_BR": true, // Portuguese (Brazil)
71 | "ro_RO": false, // Romanian (Romania)
72 | "ru_RU": false, // Russian (Russia)
73 | "es_ES": true, // Spanish (Spain)
74 | "ca_ES": true, // Catalan (Spain)
75 | "sv_SE": true, // Swedish (Sweden)
76 | "tr_TR": false, // Turkish (Turkey)
77 | "uk_UA": false, // Ukrainian (Ukraine)
78 | "bg_BG": false, // Bulgarian (Bulgaria)
79 | "zh_CN": false, // Chinese (Mainland)
80 | "zh_TW": false, // Chinese (Taiwan)
81 | "zh_HK": false, // Chinese (Hong Kong)
82 | "ko_KR": false, // Korean (Korea)
83 | "ja_JP": false, // Japanese (Japan)
84 | "el_GR": false, // Greek (Greece)
85 | "id_ID": true, // Indonesian (Indonesia)
86 | "fr_GP": true, // French (Guadeloupe)
87 | "fr_LU": true, // French (Luxembourg)
88 | "fr_MQ": true, // French (Martinique)
89 | "fr_RE": true, // French (Reunion)
90 | "fr_GF": true, // French (French Guiana)
91 | "cs_CZ": false, // Czech (Czech Republic)
92 | "sl_SI": false, // Slovenian (Slovenia)
93 | "lt_LT": false, // Lithuanian (Lithuania)
94 | "th_TH": false, // Thai (Thailand)
95 | "uz_UZ": true, // Uzbek (Uzbekistan)
96 | }
97 |
98 | type Calendar struct {
99 | WantBeginMonth int
100 | WantEndMonth int
101 | WantYear int
102 | OptFont string
103 | OptFooter string
104 | OptOrientation string
105 | OptSmall bool
106 | OptPaperformat string
107 | OptLocale string
108 | OptHideOtherMonths bool
109 | OptWallpaper string
110 | OptHideMoon bool
111 | OptHideWeek bool
112 | OptHideDOY bool
113 | OptPhoto string
114 | OptPlain bool
115 | OptConfig string
116 | OptConfigs []string
117 | OptPhotos string
118 | OptFontScale float64
119 | OptNocolor bool
120 | EventList []gDate
121 | OptCutWeekday int
122 | OptFillpattern string
123 | OptYearSpread int
124 | OptICS []string
125 | OptMargin string
126 | }
127 |
128 | func New(b int, e int, y int) *Calendar {
129 | return &Calendar{b, e, y,
130 | "serif", // OptFont
131 | "", // OptFooter
132 | "L", // OptOrientation P=portrait
133 | false, // OptSmall
134 | "A4", // OptPaperformat
135 | "en_US", // OptLocale
136 | false, // OptHideOtherMonths
137 | "", // OptWallpaper
138 | false, // OptHideMoon
139 | false, // OptHideWeek
140 | false, // OptHideDOY
141 | "", // OptPhoto
142 | false, // OptPlain
143 | "", // OptConfig
144 | nil, // OptConfigs
145 | "", // OptPhotos
146 | 1.0, // OptFontScale
147 | false, // OptNocolor
148 | nil, // EventList
149 | 0, // OptCutWeekday
150 | "", // OptFillpattern
151 | 1, // OptYearSpread
152 | nil, // OptICS
153 | "", // OptMargin
154 | }
155 | }
156 |
157 | // gDate is a type to store single events
158 | type gDate struct {
159 | Month time.Month
160 | Day int
161 | Text string
162 | Weekday string
163 | Image string
164 | }
165 |
166 | // Gocaldate is an XML type to store single events
167 | type Gocaldate struct {
168 | Date string `xml:"date,attr"`
169 | Text string `xml:"text,attr"`
170 | Image string `xml:"image,attr"`
171 | // Month time.Month
172 | // Day int
173 | // Weekday string
174 | }
175 |
176 | // monthRange stores begin and end month of the year
177 | type monthRange struct {
178 | begin int
179 | end int
180 | }
181 |
182 | // myPdf is an anonymous struct that allows to define methods on non-local types
183 | type myPdf struct {
184 | *gofpdf.Fpdf
185 | moonSize float64
186 | }
187 |
188 | func (pdf myPdf) fullMoon(x, y float64) {
189 | pdf.Circle(x, y, pdf.moonSize, "D")
190 | }
191 |
192 | func (pdf myPdf) newMoon(x, y float64) {
193 | pdf.Circle(x, y, pdf.moonSize, "F")
194 | }
195 |
196 | func (pdf myPdf) firstQuarter(x, y float64) {
197 | pdf.Arc(x, y, pdf.moonSize, pdf.moonSize, 0.0, 90.0, 270.0, "F")
198 | }
199 |
200 | func (pdf myPdf) lastQuarter(x, y float64) {
201 | pdf.Arc(x, y, pdf.moonSize, pdf.moonSize, 0.0, 270.0, 270.0+180.0, "F")
202 | }
203 |
204 | type pdfWriter struct {
205 | pdf *gofpdf.Fpdf
206 | fl *os.File
207 | pdfFilename string
208 | }
209 |
210 | func (pw *pdfWriter) Write(p []byte) (n int, err error) {
211 | if pw.pdf.Ok() {
212 | return pw.fl.Write(p)
213 | }
214 | return
215 | }
216 |
217 | func (pw *pdfWriter) Close() (err error) {
218 | if pw.fl != nil {
219 | pw.fl.Close()
220 | pw.fl = nil
221 | }
222 | if pw.pdf.Ok() {
223 | fmt.Printf("Generated '%v'.\n", pw.pdfFilename)
224 | } else {
225 | fmt.Printf("%s\n", pw.pdf.Error())
226 | }
227 | return
228 | }
229 |
230 | func docWriter(pdf *gofpdf.Fpdf, fname string) *pdfWriter {
231 | pw := new(pdfWriter)
232 | pw.pdfFilename = fname
233 | pw.pdf = pdf
234 | if pdf.Ok() {
235 | var err error
236 | pw.fl, err = os.Create(pw.pdfFilename)
237 | if err != nil {
238 | pdf.SetErrorf("# Error opening output file '%s'", pw.pdfFilename)
239 | }
240 | }
241 | return pw
242 | }
243 |
244 | func (g *Calendar) WantFillMode(s string) bool {
245 | if strings.Index(g.OptFillpattern, s) != -1 {
246 | return true
247 | }
248 | return false
249 | }
250 |
251 | func (g *Calendar) SetPlain() {
252 | g.OptPlain = true
253 | }
254 |
255 | func (g *Calendar) SetHideOtherMonth() {
256 | g.OptHideOtherMonths = true
257 | }
258 |
259 | func (g *Calendar) SetHideDOY() {
260 | g.OptHideDOY = true
261 | }
262 |
263 | func (g *Calendar) SetHideMoon() {
264 | g.OptHideMoon = true
265 | }
266 |
267 | func (g *Calendar) SetHideWeek() {
268 | g.OptHideWeek = true
269 | }
270 |
271 | func (g *Calendar) SetNocolor() {
272 | g.OptNocolor = true
273 | }
274 |
275 | func (g *Calendar) SetSmall() {
276 | g.OptSmall = true
277 | }
278 |
279 | func (g *Calendar) SetYearSpread(frac int) {
280 | switch frac {
281 | case 1:
282 | fallthrough
283 | case 2:
284 | fallthrough
285 | case 3:
286 | fallthrough
287 | case 4:
288 | fallthrough
289 | case 6:
290 | fallthrough
291 | case 12:
292 | g.OptYearSpread = frac
293 | }
294 | }
295 |
296 | func (g *Calendar) SetFont(f string) {
297 | g.OptFont = f
298 | }
299 |
300 | func (g *Calendar) SetFontScale(f float64) {
301 | g.OptFontScale = f
302 | }
303 |
304 | func (g *Calendar) SetPhotos(f string) {
305 | g.OptPhotos = f
306 | }
307 |
308 | func (g *Calendar) SetPhoto(f string) {
309 | g.OptPhoto = f
310 | }
311 |
312 | func (g *Calendar) SetConfig(f string) {
313 | g.OptConfig = f
314 | }
315 |
316 | func (g *Calendar) AddICS(f string) {
317 | g.OptICS = append(g.OptICS, f)
318 | }
319 |
320 | func (g *Calendar) AddConfig(f string) {
321 | g.OptConfigs = append(g.OptConfigs, f)
322 | }
323 |
324 | func (g *Calendar) SetLocale(f string) {
325 | g.OptLocale = f
326 | }
327 |
328 | func (g *Calendar) SetOrientation(f string) {
329 | g.OptOrientation = f
330 | }
331 |
332 | func (g *Calendar) SetWallpaper(f string) {
333 | g.OptWallpaper = f
334 | }
335 |
336 | func (g *Calendar) SetFooter(f string) {
337 | g.OptFooter = f
338 | }
339 |
340 | func (g *Calendar) SetMargin(f string) {
341 | g.OptMargin = f
342 | }
343 |
344 | func (g *Calendar) SetFillpattern(f string) {
345 | g.OptFillpattern = f
346 | }
347 |
348 | func (g *Calendar) AddEvent(day int, month int, text string, image string) {
349 | gcd := gDate{time.Month(month), int(day), text, "", image}
350 | g.EventList = append(g.EventList, gcd)
351 | }
352 |
353 | func (g *Calendar) SetPaperformat(f string) {
354 | g.OptPaperformat = f
355 | }
356 |
357 | func (g *Calendar) WantFill(i int, j int, wd time.Weekday) bool {
358 |
359 | if wd == time.Monday && g.WantFillMode("1") {
360 | return true
361 | }
362 |
363 | if wd == time.Tuesday && g.WantFillMode("2") {
364 | return true
365 | }
366 |
367 | if wd == time.Wednesday && g.WantFillMode("3") {
368 | return true
369 | }
370 |
371 | if wd == time.Thursday && g.WantFillMode("4") {
372 | return true
373 | }
374 |
375 | if wd == time.Friday && g.WantFillMode("5") {
376 | return true
377 | }
378 |
379 | if wd == time.Saturday && g.WantFillMode("6") {
380 | return true
381 | }
382 |
383 | if wd == time.Sunday && g.WantFillMode("7") {
384 | return true
385 | }
386 |
387 | if wd == time.Sunday && g.WantFillMode("S") {
388 | return true
389 | }
390 |
391 | if wd == time.Saturday && g.WantFillMode("s") {
392 | return true
393 | }
394 |
395 | if i%2 == 0 && g.WantFillMode("Y") {
396 | return true
397 | }
398 |
399 | if (i+1)%2 == 0 && g.WantFillMode("y") {
400 | return true
401 | }
402 |
403 | if j%2 == 0 && g.WantFillMode("X") {
404 | return true
405 | }
406 |
407 | if (j+1)%2 == 0 && g.WantFillMode("x") {
408 | return true
409 | }
410 |
411 | if (j+i)%2 == 0 && g.WantFillMode("c") {
412 | return true
413 | }
414 |
415 | if (j+i+1)%2 == 0 && g.WantFillMode("C") {
416 | return true
417 | }
418 |
419 | return false
420 | }
421 |
422 | func getLanguage(inLanguage string) (outLanguage string) {
423 | // First try Environment
424 | outLanguage = os.Getenv("LANG")
425 |
426 | // If set on the cmdline, override
427 | if inLanguage != "" {
428 | outLanguage = inLanguage
429 | }
430 |
431 | // if we don't know that language, fall back to en.
432 | if testedLanguage[outLanguage] != true {
433 | outLanguage = "en_US"
434 | }
435 | return
436 | }
437 |
438 | func (g *Calendar) AddWallpaper(pdf *gofpdf.Fpdf, fontTempdir string, PAGEWIDTH float64, PAGEHEIGHT float64) {
439 | wallpaperFilename := g.OptWallpaper
440 | if strings.HasPrefix(wallpaperFilename, "http://") {
441 | wallpaperFilename = downloadFile(g.OptWallpaper, fontTempdir)
442 | }
443 | pdf.Image(wallpaperFilename, 0, 0, PAGEWIDTH, PAGEHEIGHT, false, "", 0, "")
444 | }
445 |
446 | func (g *Calendar) CreateYearCalendarInverse(fn string) {
447 |
448 | var fontTempdir string
449 | var fontScale = g.OptFontScale
450 | var calFont = g.OptFont
451 |
452 | if g.OptSmall == true {
453 | fontScale = 0.75
454 | }
455 |
456 | wantyear := g.WantYear
457 |
458 | calFont, fontTempdir = processFont(calFont)
459 |
460 | pdf := gofpdf.New(g.OptOrientation, "mm", g.OptPaperformat, fontTempdir)
461 | pdf.AddFont(calFont, "", calFont+".json")
462 |
463 | pdf.SetFillColor(LIGHTGREY, LIGHTGREY, LIGHTGREY)
464 | pdf.SetMargins(10.0, 5.0, 10.0)
465 | pdf.SetTitle("Created with Gocal", true)
466 |
467 | PAGEWIDTH, PAGEHEIGHT, _ := pdf.PageSize(0)
468 | if g.OptOrientation != "P" {
469 | PAGEWIDTH, PAGEHEIGHT = PAGEHEIGHT, PAGEWIDTH
470 | }
471 |
472 | cw := (PAGEWIDTH - 2*MARGIN) / 12.5
473 | ch := (PAGEHEIGHT - 2*MARGIN) / 32
474 | currentLanguage := getLanguage(g.OptLocale)
475 | localizedWeekdayNames := getLocalizedWeekdayNames(currentLanguage, 2)
476 | localizedMonthNames := getLocalizedMonthNames(currentLanguage)
477 |
478 | monthFracture := g.OptYearSpread
479 | cw = cw * float64(monthFracture)
480 | monthOnePage := 12 / monthFracture
481 |
482 | for pageCount := 0; pageCount < monthFracture; pageCount++ {
483 | pdf.AddPage()
484 |
485 | pdf.SetTextColor(BLACK, BLACK, BLACK)
486 | pdf.SetFont(calFont, "", HEADERFONTSIZE*fontScale)
487 | pdf.CellFormat(PAGEWIDTH-MARGIN, MARGIN, fmt.Sprintf("%d", wantyear), "", 0, "C", false, 0, "")
488 |
489 | if g.OptWallpaper != "" {
490 | g.AddWallpaper(pdf, fontTempdir, PAGEWIDTH, PAGEHEIGHT)
491 | }
492 |
493 | pdf.Ln(-1)
494 |
495 | pdf.SetTextColor(BLACK, BLACK, BLACK)
496 | pdf.CellFormat(cw*0.5/float64(monthFracture), ch*0.75, "", "1", 0, "C", false, 0, "")
497 |
498 | pdf.SetTextColor(BLACK, BLACK, BLACK)
499 | pdf.SetFont(calFont, "", FOOTERFONTSIZE*fontScale*0.8)
500 | pdf.SetFillColor(LIGHTGREY, LIGHTGREY, LIGHTGREY)
501 | for mo := pageCount*monthOnePage + 1; mo <= pageCount*monthOnePage+monthOnePage; mo++ {
502 | pdf.CellFormat(cw, ch*0.75, fmt.Sprintf("%s", localizedMonthNames[mo]), "1", 0, "C", false, 0, "")
503 | }
504 | pdf.Ln(-1)
505 | pdf.SetFont(calFont, "", MONTHDAYFONTSIZE*fontScale*0.25)
506 | for i := 1; i <= 31; i++ {
507 | pdf.SetTextColor(BLACK, BLACK, BLACK)
508 | pdf.CellFormat(cw*0.5/float64(monthFracture), ch*0.9, fmt.Sprintf("%d", i), "1", 0, "C", false, 0, "")
509 | for j := pageCount*monthOnePage + 1; j <= pageCount*monthOnePage+monthOnePage; j++ {
510 | tDay := time.Date(wantyear, time.Month(j), i, 0, 0, 0, 0, time.UTC)
511 | wd := localizedWeekdayNames[(tDay.Weekday()+1)%7]
512 |
513 | if (tDay.Weekday() == time.Saturday || tDay.Weekday() == time.Sunday) && !g.OptNocolor {
514 | pdf.SetTextColor(255, 0, 0) // RED
515 | } else {
516 | pdf.SetTextColor(BLACK, BLACK, BLACK)
517 | }
518 |
519 | _, readbackMonth, _ := tDay.Date()
520 | if int(readbackMonth) == int(j) {
521 |
522 | // Day of year, lower right
523 | if g.OptHideDOY == false && int(tDay.Month()) == j {
524 | doy := julian.DayOfYearGregorian(wantyear, int(time.Month(j)), int(tDay.Day()))
525 | pdf.SetFont(calFont, "", DOYFONTSIZE*fontScale*0.5)
526 | pdf.CellFormat(cw, ch*0.9, fmt.Sprintf("%d", doy), "1", 0, "BR", false, 0, "")
527 | pdf.SetX(pdf.GetX() - cw) // reset
528 | }
529 | // Add week number, lower left
530 | if tDay.Weekday() == time.Monday && g.OptHideWeek == false {
531 | pdf.SetFont(calFont, "", WEEKFONTSIZE*0.5*fontScale)
532 | _, weeknr := tDay.ISOWeek()
533 | pdf.CellFormat(cw, ch*0.9, fmt.Sprintf("W %d", weeknr), "1", 0, "BL", false, 0, "")
534 | pdf.SetX(pdf.GetX() - cw) // reset
535 | }
536 |
537 | fillBox := g.WantFill(i, j, tDay.Weekday())
538 |
539 | pdf.SetFont(calFont, "", MONTHDAYFONTSIZE*fontScale*0.25)
540 | pdf.CellFormat(cw, ch*0.9, fmt.Sprintf("%s", wd), "1", 0, "TL", fillBox, 0, "")
541 | } else {
542 | // empty cell to skip ahead
543 | pdf.CellFormat(cw, ch*0.9, "", "1", 0, "TL", false, 0, "")
544 | }
545 | }
546 | pdf.Ln(-1)
547 | }
548 |
549 | pdf.Ln(-1)
550 | pdf.SetTextColor(DARKGREY, DARKGREY, DARKGREY)
551 | pdf.SetFont(calFont, "", FOOTERFONTSIZE*fontScale)
552 | pdf.Text(0.50*PAGEWIDTH-pdf.GetStringWidth(g.OptFooter)*0.5, 0.95*PAGEHEIGHT, fmt.Sprintf("%s", g.OptFooter))
553 |
554 |
555 | pdf.TransformBegin()// TODO Hardcoded A4 portrait
556 | ctrX := 210.0 * 0.96
557 | ctrY := 297.0 * 0.05
558 | pdf.TransformRotate(270, ctrX, ctrY)
559 | pdf.Text(ctrX, ctrY, fmt.Sprintf("%s", g.OptMargin))
560 | pdf.TransformEnd()
561 | }
562 |
563 | pdf.OutputAndClose(docWriter(pdf, fn))
564 | removeTempdir(fontTempdir)
565 | }
566 |
567 | func (g *Calendar) CreateYearCalendar(fn string) {
568 |
569 | var fontTempdir string
570 | var fontScale = g.OptFontScale
571 | var calFont = g.OptFont
572 |
573 | if g.OptSmall == true {
574 | fontScale = 0.75
575 | }
576 |
577 | wantyear := g.WantYear
578 |
579 | calFont, fontTempdir = processFont(calFont)
580 |
581 | pdf := gofpdf.New(g.OptOrientation, "mm", g.OptPaperformat, fontTempdir)
582 | pdf.AddFont(calFont, "", calFont+".json")
583 |
584 | pdf.SetFillColor(LIGHTGREY, LIGHTGREY, LIGHTGREY)
585 | pdf.SetMargins(10.0, 5.0, 10.0)
586 | pdf.SetTitle("Created with Gocal", true)
587 |
588 | PAGEWIDTH, PAGEHEIGHT, _ := pdf.PageSize(0)
589 | if g.OptOrientation != "P" {
590 | PAGEWIDTH, PAGEHEIGHT = PAGEHEIGHT, PAGEWIDTH
591 | }
592 |
593 | currentLanguage := getLanguage(g.OptLocale)
594 | localizedWeekdayNames := getLocalizedWeekdayNames(currentLanguage, 2)
595 | localizedMonthNames := getLocalizedMonthNames(currentLanguage)
596 |
597 | monthFracture := g.OptYearSpread
598 | monthOnePage := 12 / monthFracture
599 |
600 | cw := (PAGEWIDTH - 2*MARGIN) / 32
601 | ch := (PAGEHEIGHT - 2*MARGIN) / 14
602 | ch = ch * float64(monthFracture)
603 | for pageCount := 0; pageCount < monthFracture; pageCount++ {
604 | pdf.AddPage()
605 | pdf.SetTextColor(BLACK, BLACK, BLACK)
606 |
607 | if g.OptWallpaper != "" {
608 | g.AddWallpaper(pdf, fontTempdir, PAGEWIDTH, PAGEHEIGHT)
609 | }
610 |
611 | pdf.SetFont(calFont, "", MONTHDAYFONTSIZE*fontScale)
612 | pdf.CellFormat(PAGEWIDTH-MARGIN, MARGIN, fmt.Sprintf("%d", wantyear), "", 0, "C", false, 0, "")
613 | pdf.Ln(-1)
614 |
615 | pdf.SetTextColor(BLACK, BLACK, BLACK)
616 | monthTable := func(mymonth int, myyear int) {
617 | var day int64 = 1
618 |
619 | pdf.CellFormat(cw, ch, "", "1", 0, "C", false, 0, "")
620 | for j := 1; j < 32; j++ {
621 | pdf.SetFont(calFont, "", MONTHDAYFONTSIZE*fontScale*0.25)
622 |
623 | tDay := time.Date(myyear, time.Month(mymonth), j, 0, 0, 0, 0, time.UTC)
624 | if (tDay.Weekday() == time.Saturday || tDay.Weekday() == time.Sunday) && !g.OptNocolor {
625 | pdf.SetTextColor(255, 0, 0) // RED
626 | } else {
627 | pdf.SetTextColor(BLACK, BLACK, BLACK)
628 | }
629 | // if the date is invalid, like 30.2., time.Date will still have a proper date
630 | // in this case e.g. the 1.3. We have to check if the month we put in is the
631 | // the month that arrived.
632 | _, readbackMonth, _ := tDay.Date()
633 | if int(readbackMonth) == mymonth {
634 |
635 | // Day of year, lower right
636 | if g.OptHideDOY == false && int(tDay.Month()) == mymonth && tDay.Weekday() != time.Monday {
637 | doy := julian.DayOfYearGregorian(wantyear, int(mymonth), int(tDay.Day()))
638 | pdf.SetFont(calFont, "", DOYFONTSIZE*fontScale*0.5)
639 | pdf.CellFormat(cw, ch, fmt.Sprintf("%d", doy), "1", 0, "BR", false, 0, "")
640 | pdf.SetX(pdf.GetX() - cw) // reset
641 | }
642 | // Add week number, lower left
643 | if tDay.Weekday() == time.Monday && g.OptHideWeek == false {
644 | pdf.SetFont(calFont, "", WEEKFONTSIZE*0.5*fontScale)
645 | _, weeknr := tDay.ISOWeek()
646 | pdf.CellFormat(cw, ch, fmt.Sprintf("W %d", weeknr), "1", 0, "BL", false, 0, "")
647 | pdf.SetX(pdf.GetX() - cw) // reset
648 | }
649 |
650 | fillBox := g.WantFill(mymonth, j, tDay.Weekday())
651 |
652 | pdf.SetFont(calFont, "", MONTHDAYFONTSIZE*fontScale*0.25)
653 | pdf.CellFormat(cw, ch, fmt.Sprintf("%s", localizedWeekdayNames[(tDay.Weekday()+1)%7]), "1", 0, "TL", fillBox, 0, "")
654 | day++
655 | }
656 | }
657 | }
658 |
659 | var day int64 = 1
660 |
661 | // The header cells shall not scale with the monthFracture. Undo it.
662 | var ch_header = ch / float64(monthFracture) * 0.3
663 | pdf.CellFormat(cw, ch_header, "", "1", 0, "C", false, 0, "")
664 |
665 | // top row: 1..31
666 | for j := 0; j < 31; j++ {
667 | pdf.SetFont(calFont, "", MONTHDAYFONTSIZE*fontScale*0.25)
668 | pdf.CellFormat(cw, ch_header, fmt.Sprintf("%d", day), "1", 0, "C", false, 0, "")
669 | day++
670 | }
671 | pdf.Ln(-1)
672 |
673 | //for mo := 1; mo <= totalMonth; mo++ {
674 | for mo := pageCount*monthOnePage + 1; mo <= pageCount*monthOnePage+monthOnePage; mo++ {
675 | pdf.SetTextColor(BLACK, BLACK, BLACK)
676 | pdf.SetFont(calFont, "", FOOTERFONTSIZE*fontScale*0.8)
677 | pdf.TransformBegin()
678 | x, y := pdf.GetXY()
679 | pdf.TransformRotate(90, x+cw-CELLMARGIN, y+ch-CELLMARGIN)
680 | pdf.Text(x+cw-CELLMARGIN, y+ch-CELLMARGIN*2, localizedMonthNames[mo])
681 | pdf.TransformEnd()
682 | monthTable(mo, wantyear)
683 | pdf.Ln(-1)
684 | }
685 | pdf.Ln(-1)
686 | pdf.SetTextColor(DARKGREY, DARKGREY, DARKGREY)
687 | pdf.SetFont(calFont, "", FOOTERFONTSIZE*fontScale)
688 | pdf.Text(0.50*PAGEWIDTH-pdf.GetStringWidth(g.OptFooter)*0.5, 0.95*PAGEHEIGHT, fmt.Sprintf("%s", g.OptFooter))
689 |
690 | pdf.TransformBegin()// TODO Hardcoded A4 portrait
691 | ctrX := 210.0 * 0.96
692 | ctrY := 297.0 * 0.05
693 | pdf.TransformRotate(270, ctrX, ctrY)
694 | pdf.Text(ctrX, ctrY, fmt.Sprintf("%s", g.OptMargin))
695 | pdf.TransformEnd()
696 | }
697 |
698 | pdf.OutputAndClose(docWriter(pdf, fn))
699 | removeTempdir(fontTempdir)
700 | }
701 |
702 | func getPhotolist(in string, temp string) (out [12]string) {
703 | if in != "" {
704 | for i := 0; i < 12; i++ {
705 | photoname := in
706 | if strings.HasPrefix(photoname, "http://") {
707 | photoname = downloadFile(photoname, temp)
708 | }
709 | out[i] = photoname
710 | }
711 | }
712 | return out
713 | }
714 |
715 | func getPhotoslist(in string) (out [12]string) {
716 | if in != "" {
717 | fileList, err := filepath.Glob(in + string(os.PathSeparator) + "*")
718 | if err == nil {
719 | for i := 0; i < 12; i++ {
720 | out[i] = fileList[i%len(fileList)]
721 | }
722 | } else {
723 | fmt.Printf("# There is an error in your path to photos: %v\n", err)
724 | }
725 | }
726 | return out
727 | }
728 |
729 | func (g *Calendar) CreateCalendar(fn string) {
730 |
731 | var fontTempdir string
732 | var fontScale = g.OptFontScale
733 |
734 | if g.OptPlain == true {
735 | g.SetHideOtherMonth()
736 | g.SetHideDOY()
737 | g.SetHideMoon()
738 | g.SetHideWeek()
739 | }
740 |
741 | if g.OptSmall == true {
742 | fontScale = 0.75
743 | }
744 |
745 | currentLanguage := getLanguage(g.OptLocale)
746 |
747 | var fileEventList = make([]gDate, 10000) // Maximum number of events
748 |
749 | if g.OptConfig != "" {
750 | fileEventList = readConfigurationfile(g.OptConfig)
751 | }
752 |
753 | if len(g.OptICS) > 0 {
754 | for _, evfile := range g.OptICS {
755 | thiseventList := readICSfile(evfile, g.WantYear)
756 | for _, ev := range thiseventList {
757 | fileEventList = append(fileEventList, ev)
758 | }
759 | }
760 | }
761 |
762 | if len(g.OptConfigs) > 0 {
763 | for _, evfile := range g.OptConfigs {
764 | thiseventList := readConfigurationfile(evfile)
765 | for _, ev := range thiseventList {
766 | fileEventList = append(fileEventList, ev)
767 | }
768 | }
769 | }
770 |
771 | eventList := fileEventList
772 | for _, ev := range g.EventList {
773 | eventList = append(eventList, ev)
774 | }
775 |
776 | wantyear := g.WantYear
777 | wantmonths := monthRange{g.WantBeginMonth, g.WantEndMonth}
778 | localizedMonthNames := getLocalizedMonthNames(currentLanguage)
779 | localizedWeekdayNames := getLocalizedWeekdayNames(currentLanguage, 0)
780 |
781 | var calFont = g.OptFont
782 |
783 | calFont, fontTempdir = processFont(calFont)
784 |
785 | pdf := gofpdf.New(g.OptOrientation, "mm", g.OptPaperformat, fontTempdir)
786 | pdf.SetTitle("Created with Gocal", true)
787 | pdf.AddFont(calFont, "", calFont+".json")
788 |
789 | PAGEWIDTH, PAGEHEIGHT, _ := pdf.PageSize(0)
790 | if g.OptOrientation != "P" {
791 | PAGEWIDTH, PAGEHEIGHT = PAGEHEIGHT, PAGEWIDTH
792 | }
793 |
794 | cw := (PAGEWIDTH - 2*MARGIN) / COLUMNS // cellwidth w margin
795 | ch := PAGEHEIGHT / (LINES + 2) // cellheight
796 |
797 | var photoList [12]string
798 | photoList = getPhotolist(g.OptPhoto, fontTempdir)
799 | if g.OptPhotos != "" {
800 | photoList = getPhotoslist(g.OptPhotos)
801 | }
802 | if g.OptPhoto != "" || g.OptPhotos != "" {
803 | ch *= 0.5
804 | }
805 |
806 | // Map of date to String for all days in the YEAR.
807 | moonj := make(map[string]string)
808 | computeMoonphasesJ(moonj, wantyear)
809 |
810 | calendarTable := func(mymonth int, myyear int) {
811 | pdf.SetFont(calFont, "", WEEKDAYFONTSIZE*fontScale)
812 | for weekday := 0; weekday <= 6; weekday++ { // Print weekdays in first row
813 | // The week row can be smaller
814 | pdf.CellFormat(cw, ch*0.33, localizedWeekdayNames[(weekday+2)%7], "0", 0, "C", false, 0, "")
815 | }
816 | pdf.Ln(-1)
817 |
818 | // Figure out the first day in the calendar which depends on the weekday
819 | // of the first day
820 | var day int64 = 1
821 | t := time.Date(myyear, time.Month(mymonth), 1, 0, 0, 0, 0, time.UTC)
822 |
823 | day -= int64(t.Weekday())
824 | if day > 0 { // adjust silly exception where month starts w/ Sunday.
825 | day -= 7
826 | }
827 |
828 | for i := 0; i < LINES; i++ {
829 | for j := 0; j < COLUMNS; j++ {
830 | pdf.SetFillColor(LIGHTGREY, LIGHTGREY, LIGHTGREY)
831 | today := time.Date(myyear, time.Month(mymonth), 1, 0, 0, 0, 0, time.UTC).Add(time.Duration(day) * 24 * 60 * 60 * time.Second)
832 | fill := g.WantFill(i, j, today.Weekday())
833 |
834 | // Determine color
835 | if today.Month() != time.Month(mymonth) { // GREY
836 | pdf.SetTextColor(DARKGREY, DARKGREY, DARKGREY)
837 | pdf.SetFillColor(LIGHTGREY, LIGHTGREY, LIGHTGREY)
838 | fill = false // FIXME, do we want fill here?
839 | } else if (today.Weekday() == time.Saturday || today.Weekday() == time.Sunday) && !g.OptNocolor {
840 | pdf.SetTextColor(255, 0, 0) // RED
841 | } else {
842 | pdf.SetTextColor(BLACK, BLACK, BLACK)
843 | }
844 |
845 | if g.OptHideOtherMonths == true && today.Month() != time.Month(mymonth) {
846 | pdf.SetX(pdf.GetX() + cw)
847 | day++
848 | continue
849 | }
850 | pdf.SetCellMargin(CELLMARGIN)
851 |
852 | if g.OptHideMoon == false {
853 | // Do we have a relevant moon today?
854 | todayString := today.Format("2006-01-02")
855 | if m, ok := moonj[todayString]; ok == true {
856 | x, y := pdf.GetXY()
857 | moonLocX, moonLocY := x+cw*0.82, y+ch*0.2
858 |
859 | moonsize := MOONSIZE
860 | if g.OptPhoto != "" || g.OptPhotos != "" {
861 | moonsize *= 0.6
862 | }
863 | myMoonPDF := myPdf{pdf, moonsize}
864 | pdf.SetFillColor(LIGHTGREY, LIGHTGREY, LIGHTGREY)
865 | switch m {
866 | case "Full":
867 | myMoonPDF.fullMoon(moonLocX, moonLocY)
868 | case "New":
869 | myMoonPDF.newMoon(moonLocX, moonLocY)
870 | case "First":
871 | myMoonPDF.firstQuarter(moonLocX, moonLocY)
872 | case "Last":
873 | myMoonPDF.lastQuarter(moonLocX, moonLocY)
874 | }
875 | }
876 | }
877 |
878 | // Day of year, lower right
879 | if g.OptHideDOY == false && int(today.Month()) == mymonth {
880 | doy := julian.DayOfYearGregorian(myyear, mymonth, int(today.Day()))
881 | pdf.SetFont(calFont, "", DOYFONTSIZE*fontScale)
882 | pdf.CellFormat(cw, ch, fmt.Sprintf("%d", doy), "1", 0, "BR", fill, 0, "")
883 | pdf.SetX(pdf.GetX() - cw) // reset
884 | }
885 |
886 | // Add week number, lower left
887 | if today.Weekday() == time.Monday && g.OptHideWeek == false {
888 | pdf.SetFont(calFont, "", WEEKFONTSIZE*fontScale)
889 | _, weeknr := today.ISOWeek()
890 | pdf.CellFormat(cw, ch, fmt.Sprintf("W %d", weeknr), "1", 0, "BL", fill, 0, "")
891 | pdf.SetX(pdf.GetX() - cw) // reset
892 | }
893 |
894 | // Add event text
895 | for _, ev := range eventList {
896 | if len(ev.Text) == 0 {
897 | continue
898 | }
899 | if today.Weekday().String() == string(ev.Weekday) {
900 | x, y := pdf.GetXY()
901 | pdf.SetFont(calFont, "", EVENTFONTSIZE*fontScale)
902 |
903 | if ev.Image != "" {
904 | pdf.Image(ev.Image, x, y, cw, ch, false, "", 0, "")
905 | }
906 | for i, j := range strings.Split(ev.Text, "\\n") {
907 | pdf.Text(x+0.02*cw, y+0.50*ch+float64(i)*EVENTFONTSIZE*fontScale/3.0, fmt.Sprintf("%s", j))
908 | }
909 | }
910 | if today.Day() == ev.Day && today.Month() == ev.Month {
911 | x, y := pdf.GetXY()
912 | pdf.SetFont(calFont, "", EVENTFONTSIZE*fontScale)
913 |
914 | if ev.Image != "" {
915 | pdf.Image(ev.Image, x, y, cw, ch, false, "", 0, "")
916 | }
917 | for i, j := range strings.Split(ev.Text, "\\n") {
918 | pdf.Text(x+0.02*cw, y+0.50*ch+float64(i)*EVENTFONTSIZE*fontScale/3.0, fmt.Sprintf("%s", j))
919 | }
920 | }
921 | }
922 |
923 | // day of the month, big number
924 | pdf.SetFont(calFont, "", MONTHDAYFONTSIZE*fontScale)
925 | pdf.CellFormat(cw, ch, fmt.Sprintf("%d", today.Day()), "1", 0, "TL", fill, 0, "")
926 | day++
927 | }
928 | pdf.Ln(-1)
929 | }
930 | }
931 |
932 | for mo := wantmonths.begin; mo <= wantmonths.end; mo++ {
933 | //fmt.Printf("Printing page %d\n", page)
934 | pdf.AddPage()
935 | if g.OptWallpaper != "" {
936 | g.AddWallpaper(pdf, fontTempdir, PAGEWIDTH, PAGEHEIGHT)
937 | }
938 |
939 | if g.OptPhoto != "" || g.OptPhotos != "" {
940 | photo := photoList[mo-1] // this list is zero-based.
941 | if photo != "" {
942 | pdf.Image(photo, 0, PAGEHEIGHT*0.5, PAGEWIDTH, PAGEHEIGHT*0.5, false, "", 0, "")
943 | }
944 | }
945 |
946 | pdf.SetTextColor(BLACK, BLACK, BLACK)
947 | pdf.SetFont(calFont, "", HEADERFONTSIZE*fontScale)
948 | pdf.CellFormat(PAGEWIDTH-MARGIN, MARGIN, localizedMonthNames[mo]+" "+fmt.Sprintf("%d", wantyear), "", 0, "C", false, 0, "")
949 | pdf.Ln(-1)
950 | calendarTable(mo, wantyear)
951 |
952 | pdf.Ln(-1)
953 | pdf.SetTextColor(DARKGREY, DARKGREY, DARKGREY)
954 | pdf.SetFont(calFont, "", FOOTERFONTSIZE*fontScale)
955 | pdf.Text(0.50*PAGEWIDTH-pdf.GetStringWidth(g.OptFooter)*0.5, 0.95*PAGEHEIGHT, fmt.Sprintf("%s", g.OptFooter))
956 |
957 | pdf.TransformBegin() // TODO Hardcoded A4 portrait
958 | ctrX := 210.0 * 0.96
959 | ctrY := 297.0 * 0.05
960 | pdf.TransformRotate(270, ctrX, ctrY)
961 | pdf.Text(ctrX, ctrY, fmt.Sprintf("%s", g.OptMargin))
962 | pdf.TransformEnd()
963 | }
964 | pdf.OutputAndClose(docWriter(pdf, fn))
965 | removeTempdir(fontTempdir)
966 | }
967 |
--------------------------------------------------------------------------------
/gocal_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014 Stefan Schroeder, NY, 2014-03-10
2 | //
3 | // Use of this source code is governed by a BSD-style
4 | // license that can be found in the LICENSE file
5 |
6 | package gocal_test
7 |
8 | import (
9 | "github.com/StefanSchroeder/Gocal"
10 | "os"
11 | "runtime"
12 | "testing"
13 | )
14 |
15 | var outdir = "test-output" + string(os.PathSeparator)
16 |
17 | func Test_Example00(t *testing.T) {
18 | os.Mkdir(outdir, 0777)
19 | }
20 |
21 | func Test_Example01(t *testing.T) {
22 | g := gocal.New(1, 12, 2010)
23 | g.CreateCalendar(outdir + "test-example01.pdf")
24 | }
25 |
26 | func Test_Example02(t *testing.T) {
27 | g := gocal.New(1, 1, 2011)
28 | g.SetNocolor()
29 | g.SetOrientation("L")
30 | g.CreateCalendar(outdir + "test-example02.pdf")
31 | }
32 |
33 | func Test_Example03(t *testing.T) {
34 | g := gocal.New(1, 1, 2015)
35 | g.SetOrientation("P")
36 | g.SetLocale("fr_FR")
37 | g.SetFont("sans")
38 | g.CreateCalendar(outdir + "test-example03.pdf")
39 | }
40 |
41 | func Test_Example04(t *testing.T) {
42 | g := gocal.New(1, 1, 2015)
43 | g.SetOrientation("P")
44 | g.SetPhotos("gocalendar" + string(os.PathSeparator) + "pics")
45 | g.CreateCalendar(outdir + "test-example04.pdf")
46 | }
47 |
48 | func Test_Example05(t *testing.T) {
49 | g := gocal.New(3, 4, 2013)
50 | g.SetOrientation("L")
51 | g.SetFont("mono")
52 | g.SetLocale("de_DE")
53 | g.CreateCalendar(outdir + "test-example05.pdf")
54 | }
55 |
56 | func Test_Example06(t *testing.T) {
57 | g := gocal.New(3, 4, 2013)
58 | g.SetOrientation("P")
59 | g.SetPlain()
60 | g.SetLocale("nl_NL")
61 | g.CreateCalendar(outdir + "test-example06.pdf")
62 | }
63 |
64 | func Test_Example07(t *testing.T) {
65 | g := gocal.New(3, 4, 2013)
66 | if runtime.GOOS == "windows" {
67 | g.SetFont("c:\\windows\\Fonts\\cabalett.ttf")
68 | }
69 | g.SetFooter("Windows specific Font inclusion example")
70 | g.CreateCalendar(outdir + "test-example07.pdf")
71 | }
72 |
73 | func Test_Example08(t *testing.T) {
74 | g := gocal.New(3, 4, 2013)
75 | g.SetPhoto("gocalendar" + string(os.PathSeparator) + "pics" + string(os.PathSeparator) + "taxi.JPG")
76 | g.SetOrientation("P")
77 | g.CreateCalendar(outdir + "test-example08.pdf")
78 | }
79 |
80 | func Test_Example09(t *testing.T) {
81 | g := gocal.New(3, 4, 2013)
82 | g.SetLocale("fi_FI")
83 | g.CreateCalendar(outdir + "test-example09.pdf")
84 | }
85 |
86 | func Test_Example10(t *testing.T) {
87 | g := gocal.New(3, 4, 2013)
88 | g.SetFontScale(0.5)
89 | g.CreateCalendar(outdir + "test-example10.pdf")
90 | }
91 |
92 | func Test_Example11(t *testing.T) {
93 | g := gocal.New(3, 4, 2013)
94 | g.SetSmall()
95 | g.CreateCalendar(outdir + "test-example11.pdf")
96 | }
97 |
98 | func Test_Example12(t *testing.T) {
99 | g := gocal.New(3, 4, 2013)
100 | g.SetHideOtherMonth()
101 | g.CreateCalendar(outdir + "test-example12.pdf")
102 | }
103 |
104 | func Test_Example13(t *testing.T) {
105 | g := gocal.New(3, 4, 2013)
106 | g.SetHideWeek()
107 | g.AddEvent(15, 3, "One Event", "")
108 | g.AddEvent(16, 3, "Another Event", "")
109 | g.AddEvent(17, 4, "Hedgehog\\nvisits", "")
110 | g.AddEvent(18, 4, "Day\\nof the\\nDay", "")
111 | g.SetHideMoon()
112 | g.CreateCalendar(outdir + "test-example13.pdf")
113 | }
114 |
115 | func Test_Example14(t *testing.T) {
116 | g := gocal.New(1, 12, 2013)
117 | g.SetConfig("test-gocal.xml")
118 | g.CreateCalendar(outdir + "test-example14.pdf")
119 | }
120 |
121 | func Test_Example15(t *testing.T) {
122 | g := gocal.New(1, 12, 2019)
123 | g.SetYearSpread(2)
124 | g.SetFooter("Spread 2")
125 | g.CreateYearCalendar(outdir + "test-example15.pdf")
126 | }
127 |
128 | func Test_Example16(t *testing.T) {
129 | g := gocal.New(1, 12, 2019)
130 | g.CreateYearCalendarInverse(outdir + "test-example16.pdf")
131 | }
132 |
133 | func Test_Example17(t *testing.T) {
134 | g := gocal.New(1, 12, 2019)
135 | g.SetYearSpread(4)
136 | g.SetFooter("Spread 4")
137 | g.CreateYearCalendarInverse(outdir + "test-example17.pdf")
138 | }
139 |
140 | func Test_Example18(t *testing.T) {
141 | g := gocal.New(1, 12, 2019)
142 | g.SetYearSpread(4)
143 | g.SetFooter("Spread 4")
144 | g.CreateYearCalendarInverse(outdir + "test-example18.pdf")
145 | }
146 |
147 | func Test_Example19(t *testing.T) {
148 | g := gocal.New(1, 12, 2019)
149 | g.SetYearSpread(3)
150 | g.SetFooter("Spread 3")
151 | g.CreateYearCalendarInverse(outdir + "test-example19.pdf")
152 | }
153 |
154 | func Test_Example20(t *testing.T) {
155 | g := gocal.New(1, 12, 2020)
156 | g.SetFooter("Fillmode")
157 | g.WantFillMode("C")
158 | g.CreateCalendar(outdir + "test-example20.pdf")
159 | }
160 |
161 | func Test_Example21(t *testing.T) {
162 | g := gocal.New(1, 12, 2021)
163 | g.SetFooter("Small")
164 | g.SetSmall()
165 | g.CreateCalendar(outdir + "test-example21.pdf")
166 | }
167 |
--------------------------------------------------------------------------------
/gocalendar.man:
--------------------------------------------------------------------------------
1 | .nh
2 | .TH "GOCAL AND GOCALENDAR"
3 |
4 | .SH NAME
5 | .PP
6 | Gocal is a simple clone of pcal.
7 |
8 |
9 | .SH SYNOPSIS
10 | .EX
11 | gocalendar 2024 # Create a 12-page calendar for YEAR, e.g. 2024
12 |
13 | gocalendar 5 2025 # Create a 1-page calendar for the MONTH in YEAR, e.g. 5 2025
14 |
15 | gocalendar 5 7 2026 # Create a sequence from BEGIN to END in YEAR
16 |
17 | .EE
18 |
19 |
20 | .SH DESCRIPTION
21 | .PP
22 | The project includes a cli tool and a library to create
23 | monthly calendars in PDF. By default it creates a
24 | 12-page PDF with one month per page for the current year.
25 | .br
26 | The library is called gocal, while the standalone tool is named gocalendar.
27 |
28 | .PP
29 | Gocalendar can be built with 'go build' in the gocalendar folder.
30 |
31 | .PP
32 | There is a year mode that shows the entire year on one page.
33 | Have a look at the examples to get an idea of Gocal's capabilities.
34 |
35 | .PP
36 | Gocal was built because of pcal's lack of support for UTF-8 and because I feel
37 | that Postscript is obsolete.
38 |
39 |
40 | .SH FEATURES
41 | .RS
42 | .IP \(bu 2
43 | PDF generation
44 | .IP \(bu 2
45 | Week number on every Monday
46 | .IP \(bu 2
47 | Day of year
48 | .IP \(bu 2
49 | Moon phases
50 | .IP \(bu 2
51 | Events in XML configuration file
52 | .IP \(bu 2
53 | Several languages
54 | .IP \(bu 2
55 | Wallpaper option
56 | .IP \(bu 2
57 | Photo calendar option (from single image or directory)
58 | .IP \(bu 2
59 | Page orientation and paper size option
60 | .IP \(bu 2
61 | Font selection
62 | .IP \(bu 2
63 | Year calendar (two layouts)
64 | .IP \(bu 2
65 | Import of ICS files (local file or URL)
66 |
67 | .RE
68 |
69 | .PP
70 | The main design goal of gocal is simplicity. While it is absolutely possible to create
71 | an application where every single stroke is configurable, I believe that most
72 | of you are too busy to play around with lots of options and want a pleasant
73 | calendar out-of-the-box. That's what gocal provides.
74 |
75 | .PP
76 | The power of gocal is based on the cool libraries that it includes. This
77 | implies that several of the options are actually options of the libraries, e.g.
78 | the paper format (gofpdf) or the supported languages (goodsign/monday).
79 |
80 | .PP
81 | It is suggested to hide some of the optional fields or the cells will look
82 | crowded.
83 |
84 |
85 | .SH BUILD
86 | .PP
87 | Run
88 |
89 | .EX
90 | go install github.com/StefanSchroeder/Gocal/gocalendar@latest
91 |
92 | .EE
93 |
94 | .PP
95 | This will install the \fIgocalendar\fP executable in your go-bin folder.
96 |
97 | .PP
98 | Or the long haul:
99 |
100 | .PP
101 | Run
102 |
103 | .EX
104 | go get github.com/StefanSchroeder/Gocal
105 |
106 | .EE
107 |
108 | .PP
109 | Gocal has a quite a few dependencies that go should resolve automatically.
110 |
111 | .PP
112 | To build the standalone tool, change into the gocalendar directory and run
113 |
114 | .EX
115 | go build
116 |
117 | .EE
118 |
119 | .PP
120 | You create a bunch of sample files (and in passing test gocal) by running
121 |
122 | .EX
123 | go test
124 |
125 | .EE
126 |
127 |
128 | .SH EXAMPLE LIBRARY USE
129 | .EX
130 | package main
131 | import (
132 | "github.com/StefanSchroeder/gocal"
133 | )
134 | func main() {
135 | g := gocal.New(1,12,2010)
136 | g.CreateCalendar("test-example01.pdf")
137 | }
138 |
139 | .EE
140 |
141 |
142 | .SH LICENSE
143 | .PP
144 | The license is in the LICENSE file. (It's MIT.)
145 |
146 |
147 | .SH API-DOCUMENTATION
148 | .PP
149 | For the API documentation of gocal the library visit the auto-generated docs on
150 | godoc.org
151 | \[la]https://pkg.go.dev/github.com/StefanSchroeder/Gocal\[ra]\&.
152 |
153 |
154 | .SH OPTIONS OF GOCALENDAR
155 | .SS HELP
156 | .EX
157 | -h Help: Summarizes the options.
158 |
159 | .EE
160 |
161 | .SS FOOTER
162 | .EX
163 | -f="Gocal": Footer note
164 |
165 | .EE
166 |
167 | .PP
168 | Change the string at the bottom of the page. To disable the footer, simply set
169 | it to the empty string.
170 |
171 | .SS FONT
172 | .EX
173 | -font="": font
174 |
175 | -font serif (Times lookalike)
176 | -font mono (Courier lookalike)
177 | -font sans (Arial lookalike)
178 | -font path/to/font.ttf (your favorite font)
179 |
180 | .EE
181 |
182 | .PP
183 | Set the font. Only truetype fonts are supported. Look into c:\\Windows\\Fonts on
184 | Windows and /usr/share/fonts to see what fonts you have. Gocal comes with three
185 | fonts built-in: The Gnu FreeMonoBold, FreeSerifBold and FreeSansBold. They look
186 | pretty similar to (in that order) Courier, Times and Arial and should meet all
187 | your standard font needs. These fonts are licensed under the Gnu FreeFont
188 | License which accompanies this README.txt. Read more about them at
189 | https://www.gnu.org/software/freefont. Auxiliary files are created in a
190 | temporary directory.
191 |
192 | .PP
193 | The Borel-font in the sample directory is licensed under the OPL
194 | and contained here only for testing purposes.
195 | It was downloaded from https://fontesk.com/borel-font/.
196 |
197 | .PP
198 | In addition you can provide your own TTF on the commandline if you prefer something fancy.
199 |
200 | .SS FONT SIZE
201 | .PP
202 | Font sizes relative to the default size can be set with
203 |
204 | .EX
205 | -fontscale floatingpoint number
206 |
207 | .EE
208 |
209 | .PP
210 | The default is 1.0 and typically you shouldn't need to change the font size
211 | drastically. But since weekday names in some languages might be a lot longer
212 | than in other languages, ugly collisions may occur. To avoid that you can
213 | rescale the fonts a little by setting -fontscale to 0.9. There is a shortcut
214 | to reduce the fontsizes globally to 75% of the default size to gain more room
215 | for manual notes.
216 |
217 | .EX
218 | -small
219 |
220 | .EE
221 |
222 | .SS LANGUAGE
223 | .EX
224 | -lang="": Language
225 |
226 | .EE
227 |
228 | .PP
229 | Gocal reads the LANG environment variable. If it matches one of
230 |
231 | .EX
232 | "ca_ES" "da_DK" "de_DE" "en_GB" "en_US" "es_ES" "fi_FI" "fr_CA" "fr_FR"
233 | "fr_GF" "fr_GP" "fr_LU" "fr_MQ" "fr_RE" "hu_HU" "id_ID" "it_IT" "nb_NO" "nl_BE"
234 | "nl_NL" "nn_NO" "pt_BR" "pt_PT" "sv_SE" "uz_UZ"
235 |
236 | .EE
237 |
238 | .PP
239 | the library goodsign/monday is used to translate the weekday names and month
240 | names. Although this library supports a few other languages, I found that some
241 | of the languages do not work with the fonts I tried. The language from the
242 | environment can be overridden with this parameter. If your LANG is not
243 | recognized, we default to en_US.
244 |
245 | .SS HIDING STUFF
246 | .EX
247 | -nodoy: Hide day of year
248 |
249 | -nomoon: Hide moon phases
250 |
251 | -noweek: Hide week number
252 |
253 | .EE
254 |
255 | .PP
256 | The week number according to ISO-8601 is added on every Monday by default.
257 |
258 | .EX
259 | -noother: Hide neighbormonth days
260 |
261 | .EE
262 |
263 | .PP
264 | This option hides the leading and trailing days of the neighbor months.
265 | By default these days are printed in light grey.
266 |
267 | .EX
268 | -plain This will hide everything that can be hidden (but not neighbormonth days).
269 |
270 | .EE
271 |
272 | .SS OUTPUT
273 | .EX
274 | -o="output.pdf": Output filename
275 |
276 | .EE
277 |
278 | .SS PAPER ORIENTATION
279 | .EX
280 | -p="L": Orientation (L)andscape/(P)ortrait
281 |
282 | .EE
283 |
284 | .PP
285 | Typically you want landscape for calendars without image and portrait for calendars with image.
286 |
287 | .SS PAPER FORMAT
288 | .EX
289 | -paper="A4": Paper format (A3 A4 A5 Letter Legal)
290 |
291 | .EE
292 |
293 | .SS GRAYING OUT
294 | .EX
295 | -fill configure filled grid
296 |
297 | .EE
298 |
299 | .PP
300 | Can be any combination of:
301 |
302 | .EX
303 | X even columns filled gray
304 |
305 | x odd columns filled gray
306 |
307 | Y even rows filled gray
308 |
309 | y odd rows filled gray
310 |
311 | S Sundays filled gray
312 |
313 | s Saturdays filled gray
314 |
315 | c checkerboard odd
316 |
317 | C checkerboard even
318 |
319 | 1 Monday
320 |
321 | 2 Tuesday
322 |
323 | 3 Wednesday
324 |
325 | 4 Thursday
326 |
327 | 5 Friday
328 |
329 | 6 Saturday
330 |
331 | 7 Sunday
332 |
333 | .EE
334 |
335 | .PP
336 | Example:
337 |
338 | .EX
339 | -fill "x3Y"
340 |
341 | .EE
342 |
343 | .PP
344 | The gray boxes are not transparent; therefore it doesn't make a lot
345 | of sense to combine gray boxes with a wallpaper image.
346 |
347 | .SS PHOTO / PHOTOS / WALLPAPER
348 | .EX
349 | -photo=filename: Show single photo (single image in PNG JPG GIF)
350 |
351 | .EE
352 |
353 | .PP
354 | This option will add this image to every month.
355 | The filename can be a URL, qualified with http:// and it must have a valid image extension.
356 |
357 | .EX
358 | -photos=directory: Show multiple photos (directory with PNG JPG GIF)
359 |
360 | .EE
361 |
362 | .PP
363 | e.g. gocal -photos images/
364 |
365 | .PP
366 | This option will add the twelve first files as images to the twelve month. If
367 | less than twelve files are found, the sequence will re-start after the last
368 | image. This will not work if there are non-image files in the directory (among
369 | the first twelve). The directory option does NOT support URLs.
370 |
371 | .EX
372 | -wall=filename: Show wallpaper PNG JPG GIF
373 |
374 | .EE
375 |
376 | .PP
377 | e.g. gocal -wall gopher.png
378 |
379 | .PP
380 | This option will add this image to every month as a background. You should only
381 | use images with a bright tone so that you do not obstruct the usefulness of the
382 | calendar. The filename can be a URL, and must start with http:// and must have
383 | a valid image extension.
384 |
385 | .SS YEAR CALENDAR
386 | .EX
387 | -yearA
388 |
389 | -yearB
390 |
391 | .EE
392 |
393 | .PP
394 | Two different layouts are available. One with the months on the top and the
395 | days on the left and vice versa. Obviously there is less space for the
396 | individual day in this mode. Still, many of the options are available here.
397 |
398 | .EX
399 | -spread NUMBER
400 |
401 | .EE
402 |
403 | .PP
404 | In the year calendars, the entire calendar is put on one page. Using the
405 | spread option, you can spread the year across NUMBER pages. Valid values are
406 | 1 (default), 2, 3, 4, 6 and 12. Using 12 is essentially the same as not using the
407 | year mode, because it will put every month on its own page.
408 |
409 | .PP
410 | Example:
411 |
412 | .PP
413 | -yearB -spread 4
414 |
415 | .PP
416 | This will put three month on each page.
417 |
418 |
419 | .SH EVENT FILE
420 | .PP
421 | This is a sample file event configuration file.
422 | Image can be a URL, which must start with http://
423 |
424 | .EX
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 | .EE
443 |
444 | .PP
445 | Please note the cool Anglo-Saxon/Scandinavian letters, thanks to UTF-8 support.
446 |
447 | .PP
448 | This is a sample of the configuration file for gocal. It has all the supported
449 | features. date is in MONTH/DAY format. The text may contain a literal \\n
450 | newline. For the month a * is permitted and it obviously means 'every month'.
451 | You can use a leading newline symbol to make the text wrap to the next line in
452 | case of overlap. THe optional image tag will put an image into the cell.
453 |
454 | .PP
455 | For the day an English Weekday name is permitted. It means: Every
456 | matching weekday.
457 |
458 | .PP
459 | I was considering to allow to configure all the options from the command line
460 | also as parameters in the XML, but I think it's not really that important.
461 |
462 | .PP
463 | The image can also be URL, but keep in mind, that every image will be
464 | downloaded every time, because the files are downloaded to a temporary folder
465 | which is deleted after gocalendar is done.
466 |
467 |
468 | .SH ICS ICALENDAR FILES
469 | .PP
470 | Using
471 |
472 | .EX
473 | -ics filename or URL
474 |
475 | .EE
476 |
477 | .PP
478 | you can provide one or more ICS calendar objects. The events in
479 | the calendar will be added on matching dates.
480 |
481 | .PP
482 | Timezones are ignored. There is still no automatic linebreaking
483 | and no prevention of overlap with other configuration event
484 | entries.
485 |
486 | .PP
487 | From the ICS file, the \fISUMMARY\fP attribute is added as text to
488 | the calendar.
489 |
490 | .PP
491 | Example:
492 |
493 | .EX
494 | gocalendar -ics http://www.google.com/calendar/ical/de.german%23holiday%40group.v.calendar.google.com/public/basic.ics
495 | # Add German holidays to your calendar (because why wouldn't you).
496 |
497 | .EE
498 |
499 | .PP
500 | Example:
501 |
502 | .EX
503 | gocalendar -ics my.ics
504 | # Add your own local ICS file.
505 |
506 | .EE
507 |
508 |
509 | .SH EXAMPLES
510 | .PP
511 | There is more than one way to create some example calendars.
512 |
513 | .PP
514 | You can use \fB\fCgo test\fR to validate that the library works
515 | or you can run \fB\fCmake\fR after compilation to check that the standalone
516 | tool works. Both procedures provide ample suggestions what you can do.
517 |
518 | .PP
519 | The blue frames are not part of the Gocal output, but have been
520 | added for these screenshots.
521 |
522 | .PP
523 |
524 |
525 | .EX
526 | gocalendar -o example01.pdf -p P -photos pics 1 2026
527 |
528 | .EE
529 |
530 | .PP
531 |
532 |
533 | .EX
534 | gocalendar -o example02.pdf -lang fr_FR -font sans 2027
535 |
536 | .EE
537 |
538 | .PP
539 |
540 |
541 | .EX
542 | gocalendar -o example03.pdf -wall golang-gopher.png -lang de_DE -font data/Borel-Regular.ttf 2028
543 |
544 | .EE
545 |
546 | .PP
547 |
548 |
549 | .EX
550 | gocalendar -o example04.pdf -lang de_DE -font mono 2 2029
551 |
552 | .EE
553 |
554 | .PP
555 |
556 |
557 | .EX
558 | gocalendar -o example05.pdf -lang nl_NL -plain 3 2030
559 |
560 | .EE
561 |
562 | .PP
563 |
564 |
565 | .EX
566 | gocalendar -o example06.pdf -font data/Borel-Regular.ttf -lang en_US 4 2031
567 |
568 | .EE
569 |
570 | .PP
571 |
572 |
573 | .EX
574 | gocalendar -o example07.pdf -p P -lang fr_FR -photo pics\\taxi.JPG 4 2032
575 |
576 | .EE
577 |
578 | .PP
579 |
580 |
581 | .EX
582 | gocalendar -o example08.pdf -lang fr_FR -photo golang-gopher.png 4 2033
583 |
584 | .EE
585 |
586 | .PP
587 |
588 |
589 | .EX
590 | gocalendar -o example09.pdf -lang fi_FI -font serif -p L 4 2034
591 |
592 | .EE
593 |
594 | .PP
595 |
596 |
597 | .EX
598 | gocalendar -o example10.pdf -lang fi_FI -font serif -p L 12 2035
599 |
600 | .EE
601 |
602 | .PP
603 |
604 |
605 | .EX
606 | gocalendar -o example11.pdf -lang de_DE -font sans -p L 6 9 2036
607 |
608 | .EE
609 |
610 | .PP
611 |
612 |
613 | .EX
614 | gocalendar -o example12.pdf -p P -photo http://golang.org/doc/gopher/frontpage.png 7 2037
615 |
616 | .EE
617 |
618 | .PP
619 |
620 |
621 | .EX
622 | gocalendar -o example13.pdf -font sans -noother 7 2038
623 |
624 | .EE
625 |
626 | .PP
627 |
628 |
629 | .EX
630 | gocalendar -o example14.pdf -small 2 2039
631 |
632 | .EE
633 |
634 | .PP
635 |
636 |
637 | .EX
638 | gocalendar -o example15.pdf -yearA 2040
639 |
640 | .EE
641 |
642 | .PP
643 |
644 |
645 | .EX
646 | gocalendar -o example16.pdf -yearB 2041
647 |
648 | .EE
649 |
650 | .PP
651 |
652 |
653 | .EX
654 | gocalendar -o example17.pdf -yearA -fill "c" 2042
655 |
656 | .EE
657 |
658 | .PP
659 |
660 |
661 | .EX
662 | gocalendar -o example18.pdf -yearB -fill "sS" 2043
663 |
664 | .EE
665 |
666 | .PP
667 |
668 |
669 | .EX
670 | gocalendar -o example19.pdf -ics data/german.ics 12 2023
671 |
672 | .EE
673 |
674 |
675 | .SH ROADMAP
676 | .PP
677 | This is a mature application that I use regularly and that meets all
678 | my needs. If you are looking for a fancy option, let me know by
679 | writing an issue. I will consider adding it.
680 |
681 |
682 | .SH KNOWN BUGS
683 | .RS
684 | .IP \(bu 2
685 | When you have multiple events on the same date, they are overlapping. I
686 | don't intend to fix that. Use the Newline to arrange your stuff.
687 | .IP \(bu 2
688 | Not all text will fit into the cells with some settings, because the font size is
689 | not adapted dynamically to the paper format. It's a feature, not a bug.
690 | .IP \(bu 2
691 | When using the A5 paper size, the last row of a page wraps to the next page.
692 | .IP \(bu 2
693 | Some warnings in libraries might irritate the user.
694 | .IP \(bu 2
695 | The dates and months are not validated. Nothing prevents you from trying to
696 | generate a calendar for "13 2014", which will panic.
697 |
698 | .RE
699 |
700 |
701 | .SH ACKNOWLEDGMENTS
702 | .PP
703 | I'd like to thank the developers who wrote the great libraries that \fBgocal\fP is
704 | relying on, especially Sonia Keys and Kurt Jung and Йордан Пулов.
705 |
706 |
707 | .SH COPYRIGHT
708 | .PP
709 | (C) Copyright Stefan Schröder
710 |
--------------------------------------------------------------------------------
/gocalendar/data/Borel-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/gocalendar/data/Borel-Regular.ttf
--------------------------------------------------------------------------------
/gocalendar/data/german.ics:
--------------------------------------------------------------------------------
1 | BEGIN:VCALENDAR
2 | PRODID:-//Google Inc//Google Calendar 70.9054//EN
3 | VERSION:2.0
4 | CALSCALE:GREGORIAN
5 | METHOD:PUBLISH
6 | X-WR-CALNAME:Feiertage in Deutschland
7 | X-WR-TIMEZONE:UTC
8 | X-WR-CALDESC:Feier- und Gedenktage in Deutschland
9 | BEGIN:VEVENT
10 | DTSTART;VALUE=DATE:20240519
11 | DTEND;VALUE=DATE:20240520
12 | DTSTAMP:20230402T151814Z
13 | UID:20240519_2g6ikqctap8s3hvo904mrqtfio@google.com
14 | CLASS:PUBLIC
15 | CREATED:20230320T222236Z
16 | DESCRIPTION:Gedenktag in Baden-Württemberg\, Bayern\, Berlin\, Brandenburg\
17 | , Bremen\, Hamburg\, Hessen\, Mecklenburg-Vorpommern\, Niedersachsen\, Nord
18 | rhein-Westfalen\, Rheinland-Pfalz\, Saarland\, Sachsen\, Sachsen-Anhalt\, S
19 | chleswig-Holstein\, Thüringen\nWenn Sie Gedenktage ausblenden möchten\, ruf
20 | en Sie die Google Kalender-Einstellungen auf > Feiertage in Deutschland
21 | LAST-MODIFIED:20230320T222236Z
22 | SEQUENCE:0
23 | STATUS:CONFIRMED
24 | SUMMARY:Pfingsten (regionaler Feiertag)
25 | TRANSP:TRANSPARENT
26 | END:VEVENT
27 | BEGIN:VEVENT
28 | DTSTART;VALUE=DATE:20240331
29 | DTEND;VALUE=DATE:20240401
30 | DTSTAMP:20230402T151814Z
31 | UID:20240331_je0ft9jlmr75qq6baasamvdgg8@google.com
32 | CLASS:PUBLIC
33 | CREATED:20230320T222236Z
34 | DESCRIPTION:Gedenktag in Baden-Württemberg\, Bayern\, Berlin\, Brandenburg\
35 | , Bremen\, Hamburg\, Hessen\, Mecklenburg-Vorpommern\, Niedersachsen\, Nord
36 | rhein-Westfalen\, Rheinland-Pfalz\, Saarland\, Sachsen\, Sachsen-Anhalt\, S
37 | chleswig-Holstein\, Thüringen\nWenn Sie Gedenktage ausblenden möchten\, ruf
38 | en Sie die Google Kalender-Einstellungen auf > Feiertage in Deutschland
39 | LAST-MODIFIED:20230320T222236Z
40 | SEQUENCE:0
41 | STATUS:CONFIRMED
42 | SUMMARY:Ostern (regionaler Feiertag)
43 | TRANSP:TRANSPARENT
44 | END:VEVENT
45 | BEGIN:VEVENT
46 | DTSTART;VALUE=DATE:20230409
47 | DTEND;VALUE=DATE:20230410
48 | DTSTAMP:20230402T151814Z
49 | UID:20230409_g5ltds3dg2c07ksv64etl7gv2g@google.com
50 | CLASS:PUBLIC
51 | CREATED:20230320T222236Z
52 | DESCRIPTION:Feiertag in Baden-Württemberg\, Bayern\, Berlin\, Brandenburg\,
53 | Bremen\, Hamburg\, Hessen\, Mecklenburg-Vorpommern\, Niedersachsen\, Nordr
54 | hein-Westfalen\, Rheinland-Pfalz\, Saarland\, Sachsen\, Sachsen-Anhalt\, Sc
55 | hleswig-Holstein\, Thüringen
56 | LAST-MODIFIED:20230320T222236Z
57 | SEQUENCE:0
58 | STATUS:CONFIRMED
59 | SUMMARY:Ostern (regionaler Feiertag)
60 | TRANSP:TRANSPARENT
61 | END:VEVENT
62 | BEGIN:VEVENT
63 | DTSTART;VALUE=DATE:20220417
64 | DTEND;VALUE=DATE:20220418
65 | DTSTAMP:20230402T151814Z
66 | UID:20220417_4u58nh5u45bt7c88ommlg89fmo@google.com
67 | CLASS:PUBLIC
68 | CREATED:20230320T222236Z
69 | DESCRIPTION:Gedenktag in Baden-Württemberg\, Bayern\, Berlin\, Brandenburg\
70 | , Bremen\, Hamburg\, Hessen\, Mecklenburg-Vorpommern\, Niedersachsen\, Nord
71 | rhein-Westfalen\, Rheinland-Pfalz\, Saarland\, Sachsen\, Sachsen-Anhalt\, S
72 | chleswig-Holstein\, Thüringen\nWenn Sie Gedenktage ausblenden möchten\, ruf
73 | en Sie die Google Kalender-Einstellungen auf > Feiertage in Deutschland
74 | LAST-MODIFIED:20230320T222236Z
75 | SEQUENCE:0
76 | STATUS:CONFIRMED
77 | SUMMARY:Ostern (regionaler Feiertag)
78 | TRANSP:TRANSPARENT
79 | END:VEVENT
80 | BEGIN:VEVENT
81 | DTSTART;VALUE=DATE:20220815
82 | DTEND;VALUE=DATE:20220816
83 | DTSTAMP:20230402T151814Z
84 | UID:20220815_ljb7u9seg3s5apqst9nk4k016g@google.com
85 | CLASS:PUBLIC
86 | CREATED:20230320T222236Z
87 | DESCRIPTION:Feiertag in Bayern\, Saarland\, Sachsen\, Thüringen
88 | LAST-MODIFIED:20230320T222236Z
89 | SEQUENCE:0
90 | STATUS:CONFIRMED
91 | SUMMARY:Mariä Himmelfahrt (regionaler Feiertag)
92 | TRANSP:TRANSPARENT
93 | END:VEVENT
94 | BEGIN:VEVENT
95 | DTSTART;VALUE=DATE:20240308
96 | DTEND;VALUE=DATE:20240309
97 | DTSTAMP:20230402T151814Z
98 | UID:20240308_19j6gim8p9i8temt3b6qfnrgmo@google.com
99 | CLASS:PUBLIC
100 | CREATED:20230320T222236Z
101 | DESCRIPTION:Gedenktag in Baden-Württemberg\, Baden-Württemberg\, Bayern\, B
102 | ayern\, Berlin\, Brandenburg\, Brandenburg\, Bremen\, Bremen\, Hamburg\, Ha
103 | mburg\, Hessen\, Hessen\, Mecklenburg-Vorpommern\, Mecklenburg-Vorpommern\,
104 | Niedersachsen\, Niedersachsen\, Nordrhein-Westfalen\, Nordrhein-Westfalen\
105 | , Rheinland-Pfalz\, Rheinland-Pfalz\, Saarland\, Saarland\, Sachsen\, Sachs
106 | en\, Sachsen-Anhalt\, Sachsen-Anhalt\, Schleswig-Holstein\, Schleswig-Holst
107 | ein\, Thüringen\, Thüringen\nWenn Sie Gedenktage ausblenden möchten\, rufen
108 | Sie die Google Kalender-Einstellungen auf > Feiertage in Deutschland
109 | LAST-MODIFIED:20230320T222236Z
110 | SEQUENCE:0
111 | STATUS:CONFIRMED
112 | SUMMARY:Internationaler Frauentag (regionaler Feiertag)
113 | TRANSP:TRANSPARENT
114 | END:VEVENT
115 | BEGIN:VEVENT
116 | DTSTART;VALUE=DATE:20230308
117 | DTEND;VALUE=DATE:20230309
118 | DTSTAMP:20230402T151814Z
119 | UID:20230308_6t2lthjdo5tmjg61u1jkc98i0c@google.com
120 | CLASS:PUBLIC
121 | CREATED:20230320T222236Z
122 | DESCRIPTION:Gedenktag in Baden-Württemberg\, Baden-Württemberg\, Bayern\, B
123 | ayern\, Berlin\, Brandenburg\, Brandenburg\, Bremen\, Bremen\, Hamburg\, Ha
124 | mburg\, Hessen\, Hessen\, Mecklenburg-Vorpommern\, Mecklenburg-Vorpommern\,
125 | Niedersachsen\, Niedersachsen\, Nordrhein-Westfalen\, Nordrhein-Westfalen\
126 | , Rheinland-Pfalz\, Rheinland-Pfalz\, Saarland\, Saarland\, Sachsen\, Sachs
127 | en\, Sachsen-Anhalt\, Sachsen-Anhalt\, Schleswig-Holstein\, Schleswig-Holst
128 | ein\, Thüringen\, Thüringen\nWenn Sie Gedenktage ausblenden möchten\, rufen
129 | Sie die Google Kalender-Einstellungen auf > Feiertage in Deutschland
130 | LAST-MODIFIED:20230320T222236Z
131 | SEQUENCE:0
132 | STATUS:CONFIRMED
133 | SUMMARY:Internationaler Frauentag (regionaler Feiertag)
134 | TRANSP:TRANSPARENT
135 | END:VEVENT
136 | BEGIN:VEVENT
137 | DTSTART;VALUE=DATE:20241226
138 | DTEND;VALUE=DATE:20241227
139 | DTSTAMP:20230402T151814Z
140 | UID:20241226_kd7sgllu0ssnnb36rs1kkabpm4@google.com
141 | CLASS:PUBLIC
142 | CREATED:20220922T154640Z
143 | DESCRIPTION:Gesetzlicher Feiertag
144 | LAST-MODIFIED:20220922T154640Z
145 | SEQUENCE:0
146 | STATUS:CONFIRMED
147 | SUMMARY:Zweiter Weihnachtstag
148 | TRANSP:TRANSPARENT
149 | END:VEVENT
150 | BEGIN:VEVENT
151 | DTSTART;VALUE=DATE:20231226
152 | DTEND;VALUE=DATE:20231227
153 | DTSTAMP:20230402T151814Z
154 | UID:20231226_ppk5alopsqau4h6dk8b243g5bk@google.com
155 | CLASS:PUBLIC
156 | CREATED:20220922T154640Z
157 | DESCRIPTION:Gesetzlicher Feiertag
158 | LAST-MODIFIED:20220922T154640Z
159 | SEQUENCE:0
160 | STATUS:CONFIRMED
161 | SUMMARY:Zweiter Weihnachtstag
162 | TRANSP:TRANSPARENT
163 | END:VEVENT
164 | BEGIN:VEVENT
165 | DTSTART;VALUE=DATE:20221226
166 | DTEND;VALUE=DATE:20221227
167 | DTSTAMP:20230402T151814Z
168 | UID:20221226_alo0uvg029p0tfd2a8jlrr5il8@google.com
169 | CLASS:PUBLIC
170 | CREATED:20220922T154640Z
171 | DESCRIPTION:Gesetzlicher Feiertag
172 | LAST-MODIFIED:20220922T154640Z
173 | SEQUENCE:0
174 | STATUS:CONFIRMED
175 | SUMMARY:Zweiter Weihnachtstag
176 | TRANSP:TRANSPARENT
177 | END:VEVENT
178 | BEGIN:VEVENT
179 | DTSTART;VALUE=DATE:20241208
180 | DTEND;VALUE=DATE:20241209
181 | DTSTAMP:20230402T151814Z
182 | UID:20241208_gj1sg8bbe7jooml4rn9bb99fgk@google.com
183 | CLASS:PUBLIC
184 | CREATED:20220922T154640Z
185 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
186 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
187 | LAST-MODIFIED:20220922T154640Z
188 | SEQUENCE:0
189 | STATUS:CONFIRMED
190 | SUMMARY:Zweiter Advent
191 | TRANSP:TRANSPARENT
192 | END:VEVENT
193 | BEGIN:VEVENT
194 | DTSTART;VALUE=DATE:20231210
195 | DTEND;VALUE=DATE:20231211
196 | DTSTAMP:20230402T151814Z
197 | UID:20231210_73oqt8ph1v4e9oab5h74tedrkk@google.com
198 | CLASS:PUBLIC
199 | CREATED:20220922T154640Z
200 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
201 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
202 | LAST-MODIFIED:20220922T154640Z
203 | SEQUENCE:0
204 | STATUS:CONFIRMED
205 | SUMMARY:Zweiter Advent
206 | TRANSP:TRANSPARENT
207 | END:VEVENT
208 | BEGIN:VEVENT
209 | DTSTART;VALUE=DATE:20221204
210 | DTEND;VALUE=DATE:20221205
211 | DTSTAMP:20230402T151814Z
212 | UID:20221204_luguqteroc18nhh26ar6d3fr7o@google.com
213 | CLASS:PUBLIC
214 | CREATED:20220922T154640Z
215 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
216 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
217 | LAST-MODIFIED:20220922T154640Z
218 | SEQUENCE:0
219 | STATUS:CONFIRMED
220 | SUMMARY:Zweiter Advent
221 | TRANSP:TRANSPARENT
222 | END:VEVENT
223 | BEGIN:VEVENT
224 | DTSTART;VALUE=DATE:20240920
225 | DTEND;VALUE=DATE:20240921
226 | DTSTAMP:20230402T151814Z
227 | UID:20240920_caqla46kvj0enh9tnls2q902qk@google.com
228 | CLASS:PUBLIC
229 | CREATED:20220922T154640Z
230 | DESCRIPTION:Feiertag in Thüringen
231 | LAST-MODIFIED:20220922T154640Z
232 | SEQUENCE:0
233 | STATUS:CONFIRMED
234 | SUMMARY:Weltkindertag (Thüringen)
235 | TRANSP:TRANSPARENT
236 | END:VEVENT
237 | BEGIN:VEVENT
238 | DTSTART;VALUE=DATE:20230920
239 | DTEND;VALUE=DATE:20230921
240 | DTSTAMP:20230402T151814Z
241 | UID:20230920_re6548b4e6c28mo1dttrgrlu20@google.com
242 | CLASS:PUBLIC
243 | CREATED:20220922T154640Z
244 | DESCRIPTION:Feiertag in Thüringen
245 | LAST-MODIFIED:20220922T154640Z
246 | SEQUENCE:0
247 | STATUS:CONFIRMED
248 | SUMMARY:Weltkindertag (Thüringen)
249 | TRANSP:TRANSPARENT
250 | END:VEVENT
251 | BEGIN:VEVENT
252 | DTSTART;VALUE=DATE:20241117
253 | DTEND;VALUE=DATE:20241118
254 | DTSTAMP:20230402T151814Z
255 | UID:20241117_qd1rgb9illos1a8j0cpbe9baio@google.com
256 | CLASS:PUBLIC
257 | CREATED:20220922T154640Z
258 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
259 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
260 | LAST-MODIFIED:20220922T154640Z
261 | SEQUENCE:0
262 | STATUS:CONFIRMED
263 | SUMMARY:Volkstrauertag
264 | TRANSP:TRANSPARENT
265 | END:VEVENT
266 | BEGIN:VEVENT
267 | DTSTART;VALUE=DATE:20231119
268 | DTEND;VALUE=DATE:20231120
269 | DTSTAMP:20230402T151814Z
270 | UID:20231119_l4gc3sleqr9hvrg0u7mncf5od0@google.com
271 | CLASS:PUBLIC
272 | CREATED:20220922T154640Z
273 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
274 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
275 | LAST-MODIFIED:20220922T154640Z
276 | SEQUENCE:0
277 | STATUS:CONFIRMED
278 | SUMMARY:Volkstrauertag
279 | TRANSP:TRANSPARENT
280 | END:VEVENT
281 | BEGIN:VEVENT
282 | DTSTART;VALUE=DATE:20221113
283 | DTEND;VALUE=DATE:20221114
284 | DTSTAMP:20230402T151814Z
285 | UID:20221113_vl8h0f81pa00g2kke8l5kf5da4@google.com
286 | CLASS:PUBLIC
287 | CREATED:20220922T154640Z
288 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
289 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
290 | LAST-MODIFIED:20220922T154640Z
291 | SEQUENCE:0
292 | STATUS:CONFIRMED
293 | SUMMARY:Volkstrauertag
294 | TRANSP:TRANSPARENT
295 | END:VEVENT
296 | BEGIN:VEVENT
297 | DTSTART;VALUE=DATE:20241222
298 | DTEND;VALUE=DATE:20241223
299 | DTSTAMP:20230402T151814Z
300 | UID:20241222_ujml0sf8r0hesk3gk23naos7nc@google.com
301 | CLASS:PUBLIC
302 | CREATED:20220922T154640Z
303 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
304 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
305 | LAST-MODIFIED:20220922T154640Z
306 | SEQUENCE:0
307 | STATUS:CONFIRMED
308 | SUMMARY:Vierter Advent
309 | TRANSP:TRANSPARENT
310 | END:VEVENT
311 | BEGIN:VEVENT
312 | DTSTART;VALUE=DATE:20231224
313 | DTEND;VALUE=DATE:20231225
314 | DTSTAMP:20230402T151814Z
315 | UID:20231224_c83s4kviqkh3guerfoqdmb893k@google.com
316 | CLASS:PUBLIC
317 | CREATED:20220922T154640Z
318 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
319 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
320 | LAST-MODIFIED:20220922T154640Z
321 | SEQUENCE:0
322 | STATUS:CONFIRMED
323 | SUMMARY:Vierter Advent
324 | TRANSP:TRANSPARENT
325 | END:VEVENT
326 | BEGIN:VEVENT
327 | DTSTART;VALUE=DATE:20221218
328 | DTEND;VALUE=DATE:20221219
329 | DTSTAMP:20230402T151814Z
330 | UID:20221218_ftcopo9dcdgn6t9isos96c0sec@google.com
331 | CLASS:PUBLIC
332 | CREATED:20220922T154640Z
333 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
334 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
335 | LAST-MODIFIED:20220922T154640Z
336 | SEQUENCE:0
337 | STATUS:CONFIRMED
338 | SUMMARY:Vierter Advent
339 | TRANSP:TRANSPARENT
340 | END:VEVENT
341 | BEGIN:VEVENT
342 | DTSTART;VALUE=DATE:20240509
343 | DTEND;VALUE=DATE:20240510
344 | DTSTAMP:20230402T151814Z
345 | UID:20240509_8aa7jjdj86s70dcmp4659943hc@google.com
346 | CLASS:PUBLIC
347 | CREATED:20220922T154640Z
348 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
349 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
350 | LAST-MODIFIED:20220922T154640Z
351 | SEQUENCE:0
352 | STATUS:CONFIRMED
353 | SUMMARY:Vatertag
354 | TRANSP:TRANSPARENT
355 | END:VEVENT
356 | BEGIN:VEVENT
357 | DTSTART;VALUE=DATE:20230518
358 | DTEND;VALUE=DATE:20230519
359 | DTSTAMP:20230402T151814Z
360 | UID:20230518_ajkcul854389nvbt8c7t0tdnbk@google.com
361 | CLASS:PUBLIC
362 | CREATED:20220922T154640Z
363 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
364 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
365 | LAST-MODIFIED:20220922T154640Z
366 | SEQUENCE:0
367 | STATUS:CONFIRMED
368 | SUMMARY:Vatertag
369 | TRANSP:TRANSPARENT
370 | END:VEVENT
371 | BEGIN:VEVENT
372 | DTSTART;VALUE=DATE:20240214
373 | DTEND;VALUE=DATE:20240215
374 | DTSTAMP:20230402T151814Z
375 | UID:20240214_m7nhkst2j0sfgerqhs74savdlk@google.com
376 | CLASS:PUBLIC
377 | CREATED:20220922T154640Z
378 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
379 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
380 | LAST-MODIFIED:20220922T154640Z
381 | SEQUENCE:0
382 | STATUS:CONFIRMED
383 | SUMMARY:Valentinstag
384 | TRANSP:TRANSPARENT
385 | END:VEVENT
386 | BEGIN:VEVENT
387 | DTSTART;VALUE=DATE:20230214
388 | DTEND;VALUE=DATE:20230215
389 | DTSTAMP:20230402T151814Z
390 | UID:20230214_rbscb7lkbtpe4lbvruo6r6die8@google.com
391 | CLASS:PUBLIC
392 | CREATED:20220922T154640Z
393 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
394 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
395 | LAST-MODIFIED:20220922T154640Z
396 | SEQUENCE:0
397 | STATUS:CONFIRMED
398 | SUMMARY:Valentinstag
399 | TRANSP:TRANSPARENT
400 | END:VEVENT
401 | BEGIN:VEVENT
402 | DTSTART;VALUE=DATE:20241124
403 | DTEND;VALUE=DATE:20241125
404 | DTSTAMP:20230402T151814Z
405 | UID:20241124_kkfnh9oo01dh1qn1cahqjj5en8@google.com
406 | CLASS:PUBLIC
407 | CREATED:20220922T154640Z
408 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
409 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
410 | LAST-MODIFIED:20220922T154640Z
411 | SEQUENCE:0
412 | STATUS:CONFIRMED
413 | SUMMARY:Totensonntag
414 | TRANSP:TRANSPARENT
415 | END:VEVENT
416 | BEGIN:VEVENT
417 | DTSTART;VALUE=DATE:20231126
418 | DTEND;VALUE=DATE:20231127
419 | DTSTAMP:20230402T151814Z
420 | UID:20231126_048itcbfpspglpn1ctgn8s1m60@google.com
421 | CLASS:PUBLIC
422 | CREATED:20220922T154640Z
423 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
424 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
425 | LAST-MODIFIED:20220922T154640Z
426 | SEQUENCE:0
427 | STATUS:CONFIRMED
428 | SUMMARY:Totensonntag
429 | TRANSP:TRANSPARENT
430 | END:VEVENT
431 | BEGIN:VEVENT
432 | DTSTART;VALUE=DATE:20221120
433 | DTEND;VALUE=DATE:20221121
434 | DTSTAMP:20230402T151814Z
435 | UID:20221120_mkkulpfeafh0oonqcm9l08o984@google.com
436 | CLASS:PUBLIC
437 | CREATED:20220922T154640Z
438 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
439 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
440 | LAST-MODIFIED:20220922T154640Z
441 | SEQUENCE:0
442 | STATUS:CONFIRMED
443 | SUMMARY:Totensonntag
444 | TRANSP:TRANSPARENT
445 | END:VEVENT
446 | BEGIN:VEVENT
447 | DTSTART;VALUE=DATE:20241003
448 | DTEND;VALUE=DATE:20241004
449 | DTSTAMP:20230402T151814Z
450 | UID:20241003_dfvapomfcg36flije73aknlf88@google.com
451 | CLASS:PUBLIC
452 | CREATED:20220922T154640Z
453 | DESCRIPTION:Gesetzlicher Feiertag
454 | LAST-MODIFIED:20220922T154640Z
455 | SEQUENCE:0
456 | STATUS:CONFIRMED
457 | SUMMARY:Tag der Deutschen Einheit
458 | TRANSP:TRANSPARENT
459 | END:VEVENT
460 | BEGIN:VEVENT
461 | DTSTART;VALUE=DATE:20231003
462 | DTEND;VALUE=DATE:20231004
463 | DTSTAMP:20230402T151814Z
464 | UID:20231003_up7fltq2c4nt3b13i5lngaoq2o@google.com
465 | CLASS:PUBLIC
466 | CREATED:20220922T154640Z
467 | DESCRIPTION:Gesetzlicher Feiertag
468 | LAST-MODIFIED:20220922T154640Z
469 | SEQUENCE:0
470 | STATUS:CONFIRMED
471 | SUMMARY:Tag der Deutschen Einheit
472 | TRANSP:TRANSPARENT
473 | END:VEVENT
474 | BEGIN:VEVENT
475 | DTSTART;VALUE=DATE:20221003
476 | DTEND;VALUE=DATE:20221004
477 | DTSTAMP:20230402T151814Z
478 | UID:20221003_ucmbr6bofu9rkspip7lvn9nj9o@google.com
479 | CLASS:PUBLIC
480 | CREATED:20220922T154640Z
481 | DESCRIPTION:Gesetzlicher Feiertag
482 | LAST-MODIFIED:20220922T154640Z
483 | SEQUENCE:0
484 | STATUS:CONFIRMED
485 | SUMMARY:Tag der Deutschen Einheit
486 | TRANSP:TRANSPARENT
487 | END:VEVENT
488 | BEGIN:VEVENT
489 | DTSTART;VALUE=DATE:20240501
490 | DTEND;VALUE=DATE:20240502
491 | DTSTAMP:20230402T151814Z
492 | UID:20240501_cfpn15c0819flr22pdp42eskso@google.com
493 | CLASS:PUBLIC
494 | CREATED:20220922T154640Z
495 | DESCRIPTION:Gesetzlicher Feiertag
496 | LAST-MODIFIED:20220922T154640Z
497 | SEQUENCE:0
498 | STATUS:CONFIRMED
499 | SUMMARY:Tag der Arbeit
500 | TRANSP:TRANSPARENT
501 | END:VEVENT
502 | BEGIN:VEVENT
503 | DTSTART;VALUE=DATE:20230501
504 | DTEND;VALUE=DATE:20230502
505 | DTSTAMP:20230402T151814Z
506 | UID:20230501_b1h0uksh91mdsq24tfoolk9nfo@google.com
507 | CLASS:PUBLIC
508 | CREATED:20220922T154640Z
509 | DESCRIPTION:Gesetzlicher Feiertag
510 | LAST-MODIFIED:20220922T154640Z
511 | SEQUENCE:0
512 | STATUS:CONFIRMED
513 | SUMMARY:Tag der Arbeit
514 | TRANSP:TRANSPARENT
515 | END:VEVENT
516 | BEGIN:VEVENT
517 | DTSTART;VALUE=DATE:20241111
518 | DTEND;VALUE=DATE:20241112
519 | DTSTAMP:20230402T151814Z
520 | UID:20241111_9edmcjh9lkpjckank8eavgv6qk@google.com
521 | CLASS:PUBLIC
522 | CREATED:20220922T154640Z
523 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
524 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
525 | LAST-MODIFIED:20220922T154640Z
526 | SEQUENCE:0
527 | STATUS:CONFIRMED
528 | SUMMARY:St. Martin
529 | TRANSP:TRANSPARENT
530 | END:VEVENT
531 | BEGIN:VEVENT
532 | DTSTART;VALUE=DATE:20231111
533 | DTEND;VALUE=DATE:20231112
534 | DTSTAMP:20230402T151814Z
535 | UID:20231111_ggl7e6suo3dvnhevlrl46dcifk@google.com
536 | CLASS:PUBLIC
537 | CREATED:20220922T154640Z
538 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
539 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
540 | LAST-MODIFIED:20220922T154640Z
541 | SEQUENCE:0
542 | STATUS:CONFIRMED
543 | SUMMARY:St. Martin
544 | TRANSP:TRANSPARENT
545 | END:VEVENT
546 | BEGIN:VEVENT
547 | DTSTART;VALUE=DATE:20221111
548 | DTEND;VALUE=DATE:20221112
549 | DTSTAMP:20230402T151814Z
550 | UID:20221111_v8bcgmhlgjkob22de0p9mk6b3k@google.com
551 | CLASS:PUBLIC
552 | CREATED:20220922T154640Z
553 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
554 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
555 | LAST-MODIFIED:20220922T154640Z
556 | SEQUENCE:0
557 | STATUS:CONFIRMED
558 | SUMMARY:St. Martin
559 | TRANSP:TRANSPARENT
560 | END:VEVENT
561 | BEGIN:VEVENT
562 | DTSTART;VALUE=DATE:20240212
563 | DTEND;VALUE=DATE:20240213
564 | DTSTAMP:20230402T151814Z
565 | UID:20240212_05hb51q6iiubevr9kob58rpmd4@google.com
566 | CLASS:PUBLIC
567 | CREATED:20220922T154640Z
568 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
569 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
570 | LAST-MODIFIED:20220922T154640Z
571 | SEQUENCE:0
572 | STATUS:CONFIRMED
573 | SUMMARY:Rosenmontag
574 | TRANSP:TRANSPARENT
575 | END:VEVENT
576 | BEGIN:VEVENT
577 | DTSTART;VALUE=DATE:20230220
578 | DTEND;VALUE=DATE:20230221
579 | DTSTAMP:20230402T151814Z
580 | UID:20230220_h5t68r3g8o3gnhg4dcaa5voqpo@google.com
581 | CLASS:PUBLIC
582 | CREATED:20220922T154640Z
583 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
584 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
585 | LAST-MODIFIED:20220922T154640Z
586 | SEQUENCE:0
587 | STATUS:CONFIRMED
588 | SUMMARY:Rosenmontag
589 | TRANSP:TRANSPARENT
590 | END:VEVENT
591 | BEGIN:VEVENT
592 | DTSTART;VALUE=DATE:20241031
593 | DTEND;VALUE=DATE:20241101
594 | DTSTAMP:20230402T151814Z
595 | UID:20241031_r8j3772pghojg80abkgj1a0nis@google.com
596 | CLASS:PUBLIC
597 | CREATED:20220922T154640Z
598 | DESCRIPTION:Feiertag in Brandenburg\, Mecklenburg-Vorpommern\, Sachsen\, Sa
599 | chsen-Anhalt\, Thüringen\, Schleswig-Holstein\, Hamburg\, Niedersachsen\, B
600 | remen
601 | LAST-MODIFIED:20220922T154640Z
602 | SEQUENCE:0
603 | STATUS:CONFIRMED
604 | SUMMARY:Reformationstag (regionaler Feiertag)
605 | TRANSP:TRANSPARENT
606 | END:VEVENT
607 | BEGIN:VEVENT
608 | DTSTART;VALUE=DATE:20231031
609 | DTEND;VALUE=DATE:20231101
610 | DTSTAMP:20230402T151814Z
611 | UID:20231031_pf9erih9nicot7kbvesas511f8@google.com
612 | CLASS:PUBLIC
613 | CREATED:20220922T154640Z
614 | DESCRIPTION:Feiertag in Brandenburg\, Mecklenburg-Vorpommern\, Sachsen\, Sa
615 | chsen-Anhalt\, Thüringen\, Schleswig-Holstein\, Hamburg\, Niedersachsen\, B
616 | remen
617 | LAST-MODIFIED:20220922T154640Z
618 | SEQUENCE:0
619 | STATUS:CONFIRMED
620 | SUMMARY:Reformationstag (regionaler Feiertag)
621 | TRANSP:TRANSPARENT
622 | END:VEVENT
623 | BEGIN:VEVENT
624 | DTSTART;VALUE=DATE:20221031
625 | DTEND;VALUE=DATE:20221101
626 | DTSTAMP:20230402T151814Z
627 | UID:20221031_t6f50prqj0u7s0csas3j6sp8oc@google.com
628 | CLASS:PUBLIC
629 | CREATED:20220922T154640Z
630 | DESCRIPTION:Feiertag in Brandenburg\, Mecklenburg-Vorpommern\, Sachsen\, Sa
631 | chsen-Anhalt\, Thüringen\, Schleswig-Holstein\, Hamburg\, Niedersachsen\, B
632 | remen
633 | LAST-MODIFIED:20220922T154640Z
634 | SEQUENCE:0
635 | STATUS:CONFIRMED
636 | SUMMARY:Reformationstag (regionaler Feiertag)
637 | TRANSP:TRANSPARENT
638 | END:VEVENT
639 | BEGIN:VEVENT
640 | DTSTART;VALUE=DATE:20240520
641 | DTEND;VALUE=DATE:20240521
642 | DTSTAMP:20230402T151814Z
643 | UID:20240520_pj757s9jaapbu7sejuvo6ca1a0@google.com
644 | CLASS:PUBLIC
645 | CREATED:20220922T154640Z
646 | DESCRIPTION:Gesetzlicher Feiertag
647 | LAST-MODIFIED:20220922T154640Z
648 | SEQUENCE:0
649 | STATUS:CONFIRMED
650 | SUMMARY:Pfingstmontag
651 | TRANSP:TRANSPARENT
652 | END:VEVENT
653 | BEGIN:VEVENT
654 | DTSTART;VALUE=DATE:20230529
655 | DTEND;VALUE=DATE:20230530
656 | DTSTAMP:20230402T151814Z
657 | UID:20230529_0ljjg9h8dj4ft4ha2am74mul9k@google.com
658 | CLASS:PUBLIC
659 | CREATED:20220922T154640Z
660 | DESCRIPTION:Gesetzlicher Feiertag
661 | LAST-MODIFIED:20220922T154640Z
662 | SEQUENCE:0
663 | STATUS:CONFIRMED
664 | SUMMARY:Pfingstmontag
665 | TRANSP:TRANSPARENT
666 | END:VEVENT
667 | BEGIN:VEVENT
668 | DTSTART;VALUE=DATE:20230528
669 | DTEND;VALUE=DATE:20230529
670 | DTSTAMP:20230402T151814Z
671 | UID:20230528_uvgk3ka512ikg4i983f67ee6ng@google.com
672 | CLASS:PUBLIC
673 | CREATED:20220922T154640Z
674 | DESCRIPTION:Gedenktag in Baden-Württemberg\, Bayern\, Berlin\, Brandenburg\
675 | , Bremen\, Hamburg\, Hessen\, Mecklenburg-Vorpommern\, Niedersachsen\, Nord
676 | rhein-Westfalen\, Rheinland-Pfalz\, Saarland\, Sachsen\, Sachsen-Anhalt\, S
677 | chleswig-Holstein\, Thüringen\nWenn Sie Gedenktage ausblenden möchten\, ruf
678 | en Sie die Google Kalender-Einstellungen auf > Feiertage in Deutschland
679 | LAST-MODIFIED:20220922T154640Z
680 | SEQUENCE:0
681 | STATUS:CONFIRMED
682 | SUMMARY:Pfingsten (regionaler Feiertag)
683 | TRANSP:TRANSPARENT
684 | END:VEVENT
685 | BEGIN:VEVENT
686 | DTSTART;VALUE=DATE:20240324
687 | DTEND;VALUE=DATE:20240325
688 | DTSTAMP:20230402T151814Z
689 | UID:20240324_sj9gpmuc1729q1ohhjacpdp98c@google.com
690 | CLASS:PUBLIC
691 | CREATED:20220922T154640Z
692 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
693 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
694 | LAST-MODIFIED:20220922T154640Z
695 | SEQUENCE:0
696 | STATUS:CONFIRMED
697 | SUMMARY:Palmsonntag
698 | TRANSP:TRANSPARENT
699 | END:VEVENT
700 | BEGIN:VEVENT
701 | DTSTART;VALUE=DATE:20230402
702 | DTEND;VALUE=DATE:20230403
703 | DTSTAMP:20230402T151814Z
704 | UID:20230402_5od55httg17g8ot3jbkar6c44c@google.com
705 | CLASS:PUBLIC
706 | CREATED:20220922T154640Z
707 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
708 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
709 | LAST-MODIFIED:20220922T154640Z
710 | SEQUENCE:0
711 | STATUS:CONFIRMED
712 | SUMMARY:Palmsonntag
713 | TRANSP:TRANSPARENT
714 | END:VEVENT
715 | BEGIN:VEVENT
716 | DTSTART;VALUE=DATE:20240401
717 | DTEND;VALUE=DATE:20240402
718 | DTSTAMP:20230402T151814Z
719 | UID:20240401_t2b84pc5ke8it7rrsc8k6f080c@google.com
720 | CLASS:PUBLIC
721 | CREATED:20220922T154640Z
722 | DESCRIPTION:Gesetzlicher Feiertag
723 | LAST-MODIFIED:20220922T154640Z
724 | SEQUENCE:0
725 | STATUS:CONFIRMED
726 | SUMMARY:Ostermontag
727 | TRANSP:TRANSPARENT
728 | END:VEVENT
729 | BEGIN:VEVENT
730 | DTSTART;VALUE=DATE:20230410
731 | DTEND;VALUE=DATE:20230411
732 | DTSTAMP:20230402T151814Z
733 | UID:20230410_j8h7du2tgb74sgbffnnbfrp7cs@google.com
734 | CLASS:PUBLIC
735 | CREATED:20220922T154640Z
736 | DESCRIPTION:Gesetzlicher Feiertag
737 | LAST-MODIFIED:20220922T154640Z
738 | SEQUENCE:0
739 | STATUS:CONFIRMED
740 | SUMMARY:Ostermontag
741 | TRANSP:TRANSPARENT
742 | END:VEVENT
743 | BEGIN:VEVENT
744 | DTSTART;VALUE=DATE:20241206
745 | DTEND;VALUE=DATE:20241207
746 | DTSTAMP:20230402T151814Z
747 | UID:20241206_82qqhpos9gnq1e1o4alptuq4a4@google.com
748 | CLASS:PUBLIC
749 | CREATED:20220922T154640Z
750 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
751 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
752 | LAST-MODIFIED:20220922T154640Z
753 | SEQUENCE:0
754 | STATUS:CONFIRMED
755 | SUMMARY:Nikolaustag
756 | TRANSP:TRANSPARENT
757 | END:VEVENT
758 | BEGIN:VEVENT
759 | DTSTART;VALUE=DATE:20231206
760 | DTEND;VALUE=DATE:20231207
761 | DTSTAMP:20230402T151814Z
762 | UID:20231206_qhucj4hvccie8070km6a56v94k@google.com
763 | CLASS:PUBLIC
764 | CREATED:20220922T154640Z
765 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
766 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
767 | LAST-MODIFIED:20220922T154640Z
768 | SEQUENCE:0
769 | STATUS:CONFIRMED
770 | SUMMARY:Nikolaustag
771 | TRANSP:TRANSPARENT
772 | END:VEVENT
773 | BEGIN:VEVENT
774 | DTSTART;VALUE=DATE:20221206
775 | DTEND;VALUE=DATE:20221207
776 | DTSTAMP:20230402T151814Z
777 | UID:20221206_9ojhau9b1od78qg9vqku4jqve0@google.com
778 | CLASS:PUBLIC
779 | CREATED:20220922T154640Z
780 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
781 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
782 | LAST-MODIFIED:20220922T154640Z
783 | SEQUENCE:0
784 | STATUS:CONFIRMED
785 | SUMMARY:Nikolaustag
786 | TRANSP:TRANSPARENT
787 | END:VEVENT
788 | BEGIN:VEVENT
789 | DTSTART;VALUE=DATE:20240101
790 | DTEND;VALUE=DATE:20240102
791 | DTSTAMP:20230402T151814Z
792 | UID:20240101_di2uuh3656jt6ahogto7cj4te4@google.com
793 | CLASS:PUBLIC
794 | CREATED:20220922T154640Z
795 | DESCRIPTION:Gesetzlicher Feiertag
796 | LAST-MODIFIED:20220922T154640Z
797 | SEQUENCE:0
798 | STATUS:CONFIRMED
799 | SUMMARY:Neujahrstag
800 | TRANSP:TRANSPARENT
801 | END:VEVENT
802 | BEGIN:VEVENT
803 | DTSTART;VALUE=DATE:20230101
804 | DTEND;VALUE=DATE:20230102
805 | DTSTAMP:20230402T151814Z
806 | UID:20230101_67c1tm251m1bq4gv4nnq5rhm0s@google.com
807 | CLASS:PUBLIC
808 | CREATED:20220922T154640Z
809 | DESCRIPTION:Gesetzlicher Feiertag
810 | LAST-MODIFIED:20220922T154640Z
811 | SEQUENCE:0
812 | STATUS:CONFIRMED
813 | SUMMARY:Neujahrstag
814 | TRANSP:TRANSPARENT
815 | END:VEVENT
816 | BEGIN:VEVENT
817 | DTSTART;VALUE=DATE:20240512
818 | DTEND;VALUE=DATE:20240513
819 | DTSTAMP:20230402T151814Z
820 | UID:20240512_sktjbfdocrko9hag24fg0nmov8@google.com
821 | CLASS:PUBLIC
822 | CREATED:20220922T154640Z
823 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
824 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
825 | LAST-MODIFIED:20220922T154640Z
826 | SEQUENCE:0
827 | STATUS:CONFIRMED
828 | SUMMARY:Muttertag
829 | TRANSP:TRANSPARENT
830 | END:VEVENT
831 | BEGIN:VEVENT
832 | DTSTART;VALUE=DATE:20230514
833 | DTEND;VALUE=DATE:20230515
834 | DTSTAMP:20230402T151814Z
835 | UID:20230514_aoqlrth9ti6e7id9kksmis675s@google.com
836 | CLASS:PUBLIC
837 | CREATED:20220922T154640Z
838 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
839 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
840 | LAST-MODIFIED:20220922T154640Z
841 | SEQUENCE:0
842 | STATUS:CONFIRMED
843 | SUMMARY:Muttertag
844 | TRANSP:TRANSPARENT
845 | END:VEVENT
846 | BEGIN:VEVENT
847 | DTSTART;VALUE=DATE:20240815
848 | DTEND;VALUE=DATE:20240816
849 | DTSTAMP:20230402T151814Z
850 | UID:20240815_6gmksrmueo1j8hbsfj9ufrqn8o@google.com
851 | CLASS:PUBLIC
852 | CREATED:20220922T154640Z
853 | DESCRIPTION:Gedenktag in Bayern\, Saarland\, Sachsen\, Thüringen\nWenn Sie
854 | Gedenktage ausblenden möchten\, rufen Sie die Google Kalender-Einstellungen
855 | auf > Feiertage in Deutschland
856 | LAST-MODIFIED:20220922T154640Z
857 | SEQUENCE:0
858 | STATUS:CONFIRMED
859 | SUMMARY:Mariä Himmelfahrt (regionaler Feiertag)
860 | TRANSP:TRANSPARENT
861 | END:VEVENT
862 | BEGIN:VEVENT
863 | DTSTART;VALUE=DATE:20230815
864 | DTEND;VALUE=DATE:20230816
865 | DTSTAMP:20230402T151814Z
866 | UID:20230815_d389tdpnf6lnmmi15c2shkbmlg@google.com
867 | CLASS:PUBLIC
868 | CREATED:20220922T154640Z
869 | DESCRIPTION:Gedenktag in Bayern\, Saarland\, Sachsen\, Thüringen\nWenn Sie
870 | Gedenktage ausblenden möchten\, rufen Sie die Google Kalender-Einstellungen
871 | auf > Feiertage in Deutschland
872 | LAST-MODIFIED:20220922T154640Z
873 | SEQUENCE:0
874 | STATUS:CONFIRMED
875 | SUMMARY:Mariä Himmelfahrt (regionaler Feiertag)
876 | TRANSP:TRANSPARENT
877 | END:VEVENT
878 | BEGIN:VEVENT
879 | DTSTART;VALUE=DATE:20240330
880 | DTEND;VALUE=DATE:20240331
881 | DTSTAMP:20230402T151814Z
882 | UID:20240330_958hlv0b1r3bvk7168dvs9pgvg@google.com
883 | CLASS:PUBLIC
884 | CREATED:20220922T154640Z
885 | DESCRIPTION:Gedenktag in Bayern\, Hessen\, Niedersachsen\, Saarland\, Rhein
886 | land-Pfalz\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie die Google K
887 | alender-Einstellungen auf > Feiertage in Deutschland
888 | LAST-MODIFIED:20220922T154640Z
889 | SEQUENCE:0
890 | STATUS:CONFIRMED
891 | SUMMARY:Karsamstag (regionaler Feiertag)
892 | TRANSP:TRANSPARENT
893 | END:VEVENT
894 | BEGIN:VEVENT
895 | DTSTART;VALUE=DATE:20230408
896 | DTEND;VALUE=DATE:20230409
897 | DTSTAMP:20230402T151814Z
898 | UID:20230408_53ibpp9vqf3kf2e55ujccefofk@google.com
899 | CLASS:PUBLIC
900 | CREATED:20220922T154640Z
901 | DESCRIPTION:Gedenktag in Bayern\, Hessen\, Niedersachsen\, Saarland\, Rhein
902 | land-Pfalz\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie die Google K
903 | alender-Einstellungen auf > Feiertage in Deutschland
904 | LAST-MODIFIED:20220922T154640Z
905 | SEQUENCE:0
906 | STATUS:CONFIRMED
907 | SUMMARY:Karsamstag (regionaler Feiertag)
908 | TRANSP:TRANSPARENT
909 | END:VEVENT
910 | BEGIN:VEVENT
911 | DTSTART;VALUE=DATE:20240329
912 | DTEND;VALUE=DATE:20240330
913 | DTSTAMP:20230402T151814Z
914 | UID:20240329_8rj77tkmv80qdfe3it2es5op3c@google.com
915 | CLASS:PUBLIC
916 | CREATED:20220922T154640Z
917 | DESCRIPTION:Gesetzlicher Feiertag
918 | LAST-MODIFIED:20220922T154640Z
919 | SEQUENCE:0
920 | STATUS:CONFIRMED
921 | SUMMARY:Karfreitag
922 | TRANSP:TRANSPARENT
923 | END:VEVENT
924 | BEGIN:VEVENT
925 | DTSTART;VALUE=DATE:20230407
926 | DTEND;VALUE=DATE:20230408
927 | DTSTAMP:20230402T151814Z
928 | UID:20230407_lv6ggpqtsio5pui3ogvv0ib3j8@google.com
929 | CLASS:PUBLIC
930 | CREATED:20220922T154640Z
931 | DESCRIPTION:Gesetzlicher Feiertag
932 | LAST-MODIFIED:20220922T154640Z
933 | SEQUENCE:0
934 | STATUS:CONFIRMED
935 | SUMMARY:Karfreitag
936 | TRANSP:TRANSPARENT
937 | END:VEVENT
938 | BEGIN:VEVENT
939 | DTSTART;VALUE=DATE:20240508
940 | DTEND;VALUE=DATE:20240509
941 | DTSTAMP:20230402T151814Z
942 | UID:20240508_1lro5qouao044nr1tl0thompdc@google.com
943 | CLASS:PUBLIC
944 | CREATED:20220922T154640Z
945 | DESCRIPTION:Gedenktag in Berlin\, Brandenburg\, Bremen\, Mecklenburg-Vorpom
946 | mern\, Thüringen\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie die Go
947 | ogle Kalender-Einstellungen auf > Feiertage in Deutschland
948 | LAST-MODIFIED:20220922T154640Z
949 | SEQUENCE:0
950 | STATUS:CONFIRMED
951 | SUMMARY:Jahrestag der Befreiung vom Nationalsozialismus (regionaler Feierta
952 | g)
953 | TRANSP:TRANSPARENT
954 | END:VEVENT
955 | BEGIN:VEVENT
956 | DTSTART;VALUE=DATE:20230508
957 | DTEND;VALUE=DATE:20230509
958 | DTSTAMP:20230402T151814Z
959 | UID:20230508_m9ko5c8uu6tkj5pitsl7s40r64@google.com
960 | CLASS:PUBLIC
961 | CREATED:20220922T154640Z
962 | DESCRIPTION:Gedenktag in Berlin\, Brandenburg\, Bremen\, Mecklenburg-Vorpom
963 | mern\, Thüringen\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie die Go
964 | ogle Kalender-Einstellungen auf > Feiertage in Deutschland
965 | LAST-MODIFIED:20220922T154640Z
966 | SEQUENCE:0
967 | STATUS:CONFIRMED
968 | SUMMARY:Jahrestag der Befreiung vom Nationalsozialismus (regionaler Feierta
969 | g)
970 | TRANSP:TRANSPARENT
971 | END:VEVENT
972 | BEGIN:VEVENT
973 | DTSTART;VALUE=DATE:20240808
974 | DTEND;VALUE=DATE:20240809
975 | DTSTAMP:20230402T151814Z
976 | UID:20240808_i796gviakrdpp8ppdtnuo2pvp0@google.com
977 | CLASS:PUBLIC
978 | CREATED:20220922T154640Z
979 | DESCRIPTION:Feiertag in Bayern
980 | LAST-MODIFIED:20220922T154640Z
981 | SEQUENCE:0
982 | STATUS:CONFIRMED
983 | SUMMARY:Hohes Friedensfest Augsburg (Bayern)
984 | TRANSP:TRANSPARENT
985 | END:VEVENT
986 | BEGIN:VEVENT
987 | DTSTART;VALUE=DATE:20230808
988 | DTEND;VALUE=DATE:20230809
989 | DTSTAMP:20230402T151814Z
990 | UID:20230808_hcntnpnfmkgconpdrfba3o8mso@google.com
991 | CLASS:PUBLIC
992 | CREATED:20220922T154640Z
993 | DESCRIPTION:Feiertag in Bayern
994 | LAST-MODIFIED:20220922T154640Z
995 | SEQUENCE:0
996 | STATUS:CONFIRMED
997 | SUMMARY:Hohes Friedensfest Augsburg (Bayern)
998 | TRANSP:TRANSPARENT
999 | END:VEVENT
1000 | BEGIN:VEVENT
1001 | DTSTART;VALUE=DATE:20240106
1002 | DTEND;VALUE=DATE:20240107
1003 | DTSTAMP:20230402T151814Z
1004 | UID:20240106_l21ren9l3ritt1fqa2vkfag368@google.com
1005 | CLASS:PUBLIC
1006 | CREATED:20220922T154640Z
1007 | DESCRIPTION:Feiertag in Baden-Württemberg\, Bayern\, Sachsen-Anhalt
1008 | LAST-MODIFIED:20220922T154640Z
1009 | SEQUENCE:0
1010 | STATUS:CONFIRMED
1011 | SUMMARY:Heilige Drei Könige (regionaler Feiertag)
1012 | TRANSP:TRANSPARENT
1013 | END:VEVENT
1014 | BEGIN:VEVENT
1015 | DTSTART;VALUE=DATE:20230106
1016 | DTEND;VALUE=DATE:20230107
1017 | DTSTAMP:20230402T151814Z
1018 | UID:20230106_87ha9glr6qt9tqngeccmb2uipk@google.com
1019 | CLASS:PUBLIC
1020 | CREATED:20220922T154640Z
1021 | DESCRIPTION:Feiertag in Baden-Württemberg\, Bayern\, Sachsen-Anhalt
1022 | LAST-MODIFIED:20220922T154640Z
1023 | SEQUENCE:0
1024 | STATUS:CONFIRMED
1025 | SUMMARY:Heilige Drei Könige (regionaler Feiertag)
1026 | TRANSP:TRANSPARENT
1027 | END:VEVENT
1028 | BEGIN:VEVENT
1029 | DTSTART;VALUE=DATE:20241031
1030 | DTEND;VALUE=DATE:20241101
1031 | DTSTAMP:20230402T151814Z
1032 | UID:20241031_nl0r8nf2hni67n3u48j1en0oss@google.com
1033 | CLASS:PUBLIC
1034 | CREATED:20220922T154640Z
1035 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1036 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1037 | LAST-MODIFIED:20220922T154640Z
1038 | SEQUENCE:0
1039 | STATUS:CONFIRMED
1040 | SUMMARY:Halloween
1041 | TRANSP:TRANSPARENT
1042 | END:VEVENT
1043 | BEGIN:VEVENT
1044 | DTSTART;VALUE=DATE:20231031
1045 | DTEND;VALUE=DATE:20231101
1046 | DTSTAMP:20230402T151814Z
1047 | UID:20231031_no3tfdpm2t6blvtfqrh2evemv0@google.com
1048 | CLASS:PUBLIC
1049 | CREATED:20220922T154640Z
1050 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1051 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1052 | LAST-MODIFIED:20220922T154640Z
1053 | SEQUENCE:0
1054 | STATUS:CONFIRMED
1055 | SUMMARY:Halloween
1056 | TRANSP:TRANSPARENT
1057 | END:VEVENT
1058 | BEGIN:VEVENT
1059 | DTSTART;VALUE=DATE:20221031
1060 | DTEND;VALUE=DATE:20221101
1061 | DTSTAMP:20230402T151814Z
1062 | UID:20221031_uguvulc9k26jdhhlbuh27pq2cs@google.com
1063 | CLASS:PUBLIC
1064 | CREATED:20220922T154640Z
1065 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1066 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1067 | LAST-MODIFIED:20220922T154640Z
1068 | SEQUENCE:0
1069 | STATUS:CONFIRMED
1070 | SUMMARY:Halloween
1071 | TRANSP:TRANSPARENT
1072 | END:VEVENT
1073 | BEGIN:VEVENT
1074 | DTSTART;VALUE=DATE:20240328
1075 | DTEND;VALUE=DATE:20240329
1076 | DTSTAMP:20230402T151814Z
1077 | UID:20240328_2l1dsfb6ddhkb7nkk3oktk7iuc@google.com
1078 | CLASS:PUBLIC
1079 | CREATED:20220922T154640Z
1080 | DESCRIPTION:Gedenktag in Baden-Württemberg\, Bayern\, Berlin\, Brandenburg\
1081 | , Bremen\, Hamburg\, Hessen\, Mecklenburg-Vorpommern\, Niedersachsen\, Nord
1082 | rhein-Westfalen\, Rheinland-Pfalz\, Saarland\, Sachsen\, Sachsen-Anhalt\, S
1083 | chleswig-Holstein\, Thüringen\nWenn Sie Gedenktage ausblenden möchten\, ruf
1084 | en Sie die Google Kalender-Einstellungen auf > Feiertage in Deutschland
1085 | LAST-MODIFIED:20220922T154640Z
1086 | SEQUENCE:0
1087 | STATUS:CONFIRMED
1088 | SUMMARY:Gründonnerstag (regionaler Feiertag)
1089 | TRANSP:TRANSPARENT
1090 | END:VEVENT
1091 | BEGIN:VEVENT
1092 | DTSTART;VALUE=DATE:20230406
1093 | DTEND;VALUE=DATE:20230407
1094 | DTSTAMP:20230402T151814Z
1095 | UID:20230406_h84af586ipfo4sgl1ubng8j7as@google.com
1096 | CLASS:PUBLIC
1097 | CREATED:20220922T154640Z
1098 | DESCRIPTION:Gedenktag in Baden-Württemberg\, Bayern\, Berlin\, Brandenburg\
1099 | , Bremen\, Hamburg\, Hessen\, Mecklenburg-Vorpommern\, Niedersachsen\, Nord
1100 | rhein-Westfalen\, Rheinland-Pfalz\, Saarland\, Sachsen\, Sachsen-Anhalt\, S
1101 | chleswig-Holstein\, Thüringen\nWenn Sie Gedenktage ausblenden möchten\, ruf
1102 | en Sie die Google Kalender-Einstellungen auf > Feiertage in Deutschland
1103 | LAST-MODIFIED:20220922T154640Z
1104 | SEQUENCE:0
1105 | STATUS:CONFIRMED
1106 | SUMMARY:Gründonnerstag (regionaler Feiertag)
1107 | TRANSP:TRANSPARENT
1108 | END:VEVENT
1109 | BEGIN:VEVENT
1110 | DTSTART;VALUE=DATE:20240530
1111 | DTEND;VALUE=DATE:20240531
1112 | DTSTAMP:20230402T151814Z
1113 | UID:20240530_qgc2sebgj4b42fig5v31dm88u0@google.com
1114 | CLASS:PUBLIC
1115 | CREATED:20220922T154640Z
1116 | DESCRIPTION:Feiertag in Baden-Württemberg\, Bayern\, Hessen\, Nordrhein-Wes
1117 | tfalen\, Rheinland-Pfalz\, Saarland\, Sachsen\, Thüringen
1118 | LAST-MODIFIED:20220922T154640Z
1119 | SEQUENCE:0
1120 | STATUS:CONFIRMED
1121 | SUMMARY:Fronleichnam (regionaler Feiertag)
1122 | TRANSP:TRANSPARENT
1123 | END:VEVENT
1124 | BEGIN:VEVENT
1125 | DTSTART;VALUE=DATE:20230608
1126 | DTEND;VALUE=DATE:20230609
1127 | DTSTAMP:20230402T151814Z
1128 | UID:20230608_rkd0obgh7a3fkcm84msk4tobng@google.com
1129 | CLASS:PUBLIC
1130 | CREATED:20220922T154640Z
1131 | DESCRIPTION:Feiertag in Baden-Württemberg\, Bayern\, Hessen\, Nordrhein-Wes
1132 | tfalen\, Rheinland-Pfalz\, Saarland\, Sachsen\, Thüringen
1133 | LAST-MODIFIED:20220922T154640Z
1134 | SEQUENCE:0
1135 | STATUS:CONFIRMED
1136 | SUMMARY:Fronleichnam (regionaler Feiertag)
1137 | TRANSP:TRANSPARENT
1138 | END:VEVENT
1139 | BEGIN:VEVENT
1140 | DTSTART;VALUE=DATE:20240213
1141 | DTEND;VALUE=DATE:20240214
1142 | DTSTAMP:20230402T151814Z
1143 | UID:20240213_qfe1537mj36fi1h0ja1i7al8h8@google.com
1144 | CLASS:PUBLIC
1145 | CREATED:20220922T154640Z
1146 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1147 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1148 | LAST-MODIFIED:20220922T154640Z
1149 | SEQUENCE:0
1150 | STATUS:CONFIRMED
1151 | SUMMARY:Faschingsdienstag
1152 | TRANSP:TRANSPARENT
1153 | END:VEVENT
1154 | BEGIN:VEVENT
1155 | DTSTART;VALUE=DATE:20230221
1156 | DTEND;VALUE=DATE:20230222
1157 | DTSTAMP:20230402T151814Z
1158 | UID:20230221_gnvuqgkqaudf1fo6lrcgbrbusc@google.com
1159 | CLASS:PUBLIC
1160 | CREATED:20220922T154640Z
1161 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1162 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1163 | LAST-MODIFIED:20220922T154640Z
1164 | SEQUENCE:0
1165 | STATUS:CONFIRMED
1166 | SUMMARY:Faschingsdienstag
1167 | TRANSP:TRANSPARENT
1168 | END:VEVENT
1169 | BEGIN:VEVENT
1170 | DTSTART;VALUE=DATE:20241225
1171 | DTEND;VALUE=DATE:20241226
1172 | DTSTAMP:20230402T151814Z
1173 | UID:20241225_h4a3g9a7ir64jss37mt6a00r98@google.com
1174 | CLASS:PUBLIC
1175 | CREATED:20220922T154640Z
1176 | DESCRIPTION:Gesetzlicher Feiertag
1177 | LAST-MODIFIED:20220922T154640Z
1178 | SEQUENCE:0
1179 | STATUS:CONFIRMED
1180 | SUMMARY:Erster Weihnachtstag
1181 | TRANSP:TRANSPARENT
1182 | END:VEVENT
1183 | BEGIN:VEVENT
1184 | DTSTART;VALUE=DATE:20231225
1185 | DTEND;VALUE=DATE:20231226
1186 | DTSTAMP:20230402T151814Z
1187 | UID:20231225_t0rl00u26tbi35tr3moi83iht0@google.com
1188 | CLASS:PUBLIC
1189 | CREATED:20220922T154640Z
1190 | DESCRIPTION:Gesetzlicher Feiertag
1191 | LAST-MODIFIED:20220922T154640Z
1192 | SEQUENCE:0
1193 | STATUS:CONFIRMED
1194 | SUMMARY:Erster Weihnachtstag
1195 | TRANSP:TRANSPARENT
1196 | END:VEVENT
1197 | BEGIN:VEVENT
1198 | DTSTART;VALUE=DATE:20221225
1199 | DTEND;VALUE=DATE:20221226
1200 | DTSTAMP:20230402T151814Z
1201 | UID:20221225_62c0vj63fb0jgmt2tsqvcu7hfo@google.com
1202 | CLASS:PUBLIC
1203 | CREATED:20220922T154640Z
1204 | DESCRIPTION:Gesetzlicher Feiertag
1205 | LAST-MODIFIED:20220922T154640Z
1206 | SEQUENCE:0
1207 | STATUS:CONFIRMED
1208 | SUMMARY:Erster Weihnachtstag
1209 | TRANSP:TRANSPARENT
1210 | END:VEVENT
1211 | BEGIN:VEVENT
1212 | DTSTART;VALUE=DATE:20241201
1213 | DTEND;VALUE=DATE:20241202
1214 | DTSTAMP:20230402T151814Z
1215 | UID:20241201_lc4vn1gvlk1ifg9oqnbihus89c@google.com
1216 | CLASS:PUBLIC
1217 | CREATED:20220922T154640Z
1218 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1219 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1220 | LAST-MODIFIED:20220922T154640Z
1221 | SEQUENCE:0
1222 | STATUS:CONFIRMED
1223 | SUMMARY:Erster Advent
1224 | TRANSP:TRANSPARENT
1225 | END:VEVENT
1226 | BEGIN:VEVENT
1227 | DTSTART;VALUE=DATE:20231203
1228 | DTEND;VALUE=DATE:20231204
1229 | DTSTAMP:20230402T151814Z
1230 | UID:20231203_tilpr41g7be7rvt70l4q7isvj0@google.com
1231 | CLASS:PUBLIC
1232 | CREATED:20220922T154640Z
1233 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1234 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1235 | LAST-MODIFIED:20220922T154640Z
1236 | SEQUENCE:0
1237 | STATUS:CONFIRMED
1238 | SUMMARY:Erster Advent
1239 | TRANSP:TRANSPARENT
1240 | END:VEVENT
1241 | BEGIN:VEVENT
1242 | DTSTART;VALUE=DATE:20221127
1243 | DTEND;VALUE=DATE:20221128
1244 | DTSTAMP:20230402T151814Z
1245 | UID:20221127_evmk4r13ung4m9dle7do75ee6c@google.com
1246 | CLASS:PUBLIC
1247 | CREATED:20220922T154640Z
1248 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1249 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1250 | LAST-MODIFIED:20220922T154640Z
1251 | SEQUENCE:0
1252 | STATUS:CONFIRMED
1253 | SUMMARY:Erster Advent
1254 | TRANSP:TRANSPARENT
1255 | END:VEVENT
1256 | BEGIN:VEVENT
1257 | DTSTART;VALUE=DATE:20241027
1258 | DTEND;VALUE=DATE:20241028
1259 | DTSTAMP:20230402T151814Z
1260 | UID:20241027_30pvdjf1m0nlfi7pgas20r9fqo@google.com
1261 | CLASS:PUBLIC
1262 | CREATED:20220922T154640Z
1263 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1264 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1265 | LAST-MODIFIED:20220922T154640Z
1266 | SEQUENCE:0
1267 | STATUS:CONFIRMED
1268 | SUMMARY:Ende der Sommerzeit
1269 | TRANSP:TRANSPARENT
1270 | END:VEVENT
1271 | BEGIN:VEVENT
1272 | DTSTART;VALUE=DATE:20231029
1273 | DTEND;VALUE=DATE:20231030
1274 | DTSTAMP:20230402T151814Z
1275 | UID:20231029_rnb58pmgkplb1lqqu7grp75t2g@google.com
1276 | CLASS:PUBLIC
1277 | CREATED:20220922T154640Z
1278 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1279 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1280 | LAST-MODIFIED:20220922T154640Z
1281 | SEQUENCE:0
1282 | STATUS:CONFIRMED
1283 | SUMMARY:Ende der Sommerzeit
1284 | TRANSP:TRANSPARENT
1285 | END:VEVENT
1286 | BEGIN:VEVENT
1287 | DTSTART;VALUE=DATE:20221030
1288 | DTEND;VALUE=DATE:20221031
1289 | DTSTAMP:20230402T151814Z
1290 | UID:20221030_op6pdrvdfmlr6fp7j58al1m6ek@google.com
1291 | CLASS:PUBLIC
1292 | CREATED:20220922T154640Z
1293 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1294 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1295 | LAST-MODIFIED:20220922T154640Z
1296 | SEQUENCE:0
1297 | STATUS:CONFIRMED
1298 | SUMMARY:Ende der Sommerzeit
1299 | TRANSP:TRANSPARENT
1300 | END:VEVENT
1301 | BEGIN:VEVENT
1302 | DTSTART;VALUE=DATE:20241215
1303 | DTEND;VALUE=DATE:20241216
1304 | DTSTAMP:20230402T151814Z
1305 | UID:20241215_dk581lnducjhjm33fs05j2q0cg@google.com
1306 | CLASS:PUBLIC
1307 | CREATED:20220922T154640Z
1308 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1309 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1310 | LAST-MODIFIED:20220922T154640Z
1311 | SEQUENCE:0
1312 | STATUS:CONFIRMED
1313 | SUMMARY:Dritter Advent
1314 | TRANSP:TRANSPARENT
1315 | END:VEVENT
1316 | BEGIN:VEVENT
1317 | DTSTART;VALUE=DATE:20231217
1318 | DTEND;VALUE=DATE:20231218
1319 | DTSTAMP:20230402T151814Z
1320 | UID:20231217_mpp1skgvkubld87375a1n25qok@google.com
1321 | CLASS:PUBLIC
1322 | CREATED:20220922T154640Z
1323 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1324 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1325 | LAST-MODIFIED:20220922T154640Z
1326 | SEQUENCE:0
1327 | STATUS:CONFIRMED
1328 | SUMMARY:Dritter Advent
1329 | TRANSP:TRANSPARENT
1330 | END:VEVENT
1331 | BEGIN:VEVENT
1332 | DTSTART;VALUE=DATE:20221211
1333 | DTEND;VALUE=DATE:20221212
1334 | DTSTAMP:20230402T151814Z
1335 | UID:20221211_q68h7et0bl3n4evuho0n6fvl20@google.com
1336 | CLASS:PUBLIC
1337 | CREATED:20220922T154640Z
1338 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1339 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1340 | LAST-MODIFIED:20220922T154640Z
1341 | SEQUENCE:0
1342 | STATUS:CONFIRMED
1343 | SUMMARY:Dritter Advent
1344 | TRANSP:TRANSPARENT
1345 | END:VEVENT
1346 | BEGIN:VEVENT
1347 | DTSTART;VALUE=DATE:20240509
1348 | DTEND;VALUE=DATE:20240510
1349 | DTSTAMP:20230402T151814Z
1350 | UID:20240509_a1a9k4sacm6lmmljn510aofbes@google.com
1351 | CLASS:PUBLIC
1352 | CREATED:20220922T154640Z
1353 | DESCRIPTION:Gesetzlicher Feiertag
1354 | LAST-MODIFIED:20220922T154640Z
1355 | SEQUENCE:0
1356 | STATUS:CONFIRMED
1357 | SUMMARY:Christi Himmelfahrt
1358 | TRANSP:TRANSPARENT
1359 | END:VEVENT
1360 | BEGIN:VEVENT
1361 | DTSTART;VALUE=DATE:20230518
1362 | DTEND;VALUE=DATE:20230519
1363 | DTSTAMP:20230402T151814Z
1364 | UID:20230518_87qn10knesa5nt2f6d3q2scoc4@google.com
1365 | CLASS:PUBLIC
1366 | CREATED:20220922T154640Z
1367 | DESCRIPTION:Gesetzlicher Feiertag
1368 | LAST-MODIFIED:20220922T154640Z
1369 | SEQUENCE:0
1370 | STATUS:CONFIRMED
1371 | SUMMARY:Christi Himmelfahrt
1372 | TRANSP:TRANSPARENT
1373 | END:VEVENT
1374 | BEGIN:VEVENT
1375 | DTSTART;VALUE=DATE:20241120
1376 | DTEND;VALUE=DATE:20241121
1377 | DTSTAMP:20230402T151814Z
1378 | UID:20241120_mlq18o6euidbesusjjr0hp1e3k@google.com
1379 | CLASS:PUBLIC
1380 | CREATED:20220922T154640Z
1381 | DESCRIPTION:Feiertag in Sachsen
1382 | LAST-MODIFIED:20220922T154640Z
1383 | SEQUENCE:0
1384 | STATUS:CONFIRMED
1385 | SUMMARY:Buß- und Bettag (Sachsen)
1386 | TRANSP:TRANSPARENT
1387 | END:VEVENT
1388 | BEGIN:VEVENT
1389 | DTSTART;VALUE=DATE:20231122
1390 | DTEND;VALUE=DATE:20231123
1391 | DTSTAMP:20230402T151814Z
1392 | UID:20231122_m0hnmifb9hdodqeqkcgod1vqoc@google.com
1393 | CLASS:PUBLIC
1394 | CREATED:20220922T154640Z
1395 | DESCRIPTION:Feiertag in Sachsen
1396 | LAST-MODIFIED:20220922T154640Z
1397 | SEQUENCE:0
1398 | STATUS:CONFIRMED
1399 | SUMMARY:Buß- und Bettag (Sachsen)
1400 | TRANSP:TRANSPARENT
1401 | END:VEVENT
1402 | BEGIN:VEVENT
1403 | DTSTART;VALUE=DATE:20221116
1404 | DTEND;VALUE=DATE:20221117
1405 | DTSTAMP:20230402T151814Z
1406 | UID:20221116_u0qm9gc7feii59i2mm6nmgpv2k@google.com
1407 | CLASS:PUBLIC
1408 | CREATED:20220922T154640Z
1409 | DESCRIPTION:Feiertag in Sachsen
1410 | LAST-MODIFIED:20220922T154640Z
1411 | SEQUENCE:0
1412 | STATUS:CONFIRMED
1413 | SUMMARY:Buß- und Bettag (Sachsen)
1414 | TRANSP:TRANSPARENT
1415 | END:VEVENT
1416 | BEGIN:VEVENT
1417 | DTSTART;VALUE=DATE:20240331
1418 | DTEND;VALUE=DATE:20240401
1419 | DTSTAMP:20230402T151814Z
1420 | UID:20240331_7lu6a9vhlpn5kmoqq4bkjg488o@google.com
1421 | CLASS:PUBLIC
1422 | CREATED:20220922T154640Z
1423 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1424 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1425 | LAST-MODIFIED:20220922T154640Z
1426 | SEQUENCE:0
1427 | STATUS:CONFIRMED
1428 | SUMMARY:Beginn der Sommerzeit
1429 | TRANSP:TRANSPARENT
1430 | END:VEVENT
1431 | BEGIN:VEVENT
1432 | DTSTART;VALUE=DATE:20230326
1433 | DTEND;VALUE=DATE:20230327
1434 | DTSTAMP:20230402T151814Z
1435 | UID:20230326_f622nsdq94gud42llo7kdfe36k@google.com
1436 | CLASS:PUBLIC
1437 | CREATED:20220922T154640Z
1438 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1439 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1440 | LAST-MODIFIED:20220922T154640Z
1441 | SEQUENCE:0
1442 | STATUS:CONFIRMED
1443 | SUMMARY:Beginn der Sommerzeit
1444 | TRANSP:TRANSPARENT
1445 | END:VEVENT
1446 | BEGIN:VEVENT
1447 | DTSTART;VALUE=DATE:20240214
1448 | DTEND;VALUE=DATE:20240215
1449 | DTSTAMP:20230402T151814Z
1450 | UID:20240214_e7oog9n16bgg0dlpphs5b7pkvs@google.com
1451 | CLASS:PUBLIC
1452 | CREATED:20220922T154640Z
1453 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1454 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1455 | LAST-MODIFIED:20220922T154640Z
1456 | SEQUENCE:0
1457 | STATUS:CONFIRMED
1458 | SUMMARY:Aschermittwoch
1459 | TRANSP:TRANSPARENT
1460 | END:VEVENT
1461 | BEGIN:VEVENT
1462 | DTSTART;VALUE=DATE:20230222
1463 | DTEND;VALUE=DATE:20230223
1464 | DTSTAMP:20230402T151814Z
1465 | UID:20230222_8jblvn70cu1n6u8nf2av0iu99g@google.com
1466 | CLASS:PUBLIC
1467 | CREATED:20220922T154640Z
1468 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1469 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1470 | LAST-MODIFIED:20220922T154640Z
1471 | SEQUENCE:0
1472 | STATUS:CONFIRMED
1473 | SUMMARY:Aschermittwoch
1474 | TRANSP:TRANSPARENT
1475 | END:VEVENT
1476 | BEGIN:VEVENT
1477 | DTSTART;VALUE=DATE:20241101
1478 | DTEND;VALUE=DATE:20241102
1479 | DTSTAMP:20230402T151814Z
1480 | UID:20241101_gt4bmg13f1aq5e4cf6heovvusk@google.com
1481 | CLASS:PUBLIC
1482 | CREATED:20220922T154640Z
1483 | DESCRIPTION:Feiertag in Baden-Württemberg\, Bayern\, Nordrhein-Westfalen\,
1484 | Rheinland-Pfalz\, Saarland
1485 | LAST-MODIFIED:20220922T154640Z
1486 | SEQUENCE:0
1487 | STATUS:CONFIRMED
1488 | SUMMARY:Allerheiligen (regionaler Feiertag)
1489 | TRANSP:TRANSPARENT
1490 | END:VEVENT
1491 | BEGIN:VEVENT
1492 | DTSTART;VALUE=DATE:20231101
1493 | DTEND;VALUE=DATE:20231102
1494 | DTSTAMP:20230402T151814Z
1495 | UID:20231101_j2bpej98u49opl37vpc9tqa3ck@google.com
1496 | CLASS:PUBLIC
1497 | CREATED:20220922T154640Z
1498 | DESCRIPTION:Feiertag in Baden-Württemberg\, Bayern\, Nordrhein-Westfalen\,
1499 | Rheinland-Pfalz\, Saarland
1500 | LAST-MODIFIED:20220922T154640Z
1501 | SEQUENCE:0
1502 | STATUS:CONFIRMED
1503 | SUMMARY:Allerheiligen (regionaler Feiertag)
1504 | TRANSP:TRANSPARENT
1505 | END:VEVENT
1506 | BEGIN:VEVENT
1507 | DTSTART;VALUE=DATE:20221101
1508 | DTEND;VALUE=DATE:20221102
1509 | DTSTAMP:20230402T151814Z
1510 | UID:20221101_du4tuppj03t8n0r9ifu0on739g@google.com
1511 | CLASS:PUBLIC
1512 | CREATED:20220922T154640Z
1513 | DESCRIPTION:Feiertag in Baden-Württemberg\, Bayern\, Nordrhein-Westfalen\,
1514 | Rheinland-Pfalz\, Saarland
1515 | LAST-MODIFIED:20220922T154640Z
1516 | SEQUENCE:0
1517 | STATUS:CONFIRMED
1518 | SUMMARY:Allerheiligen (regionaler Feiertag)
1519 | TRANSP:TRANSPARENT
1520 | END:VEVENT
1521 | BEGIN:VEVENT
1522 | DTSTART;VALUE=DATE:20220605
1523 | DTEND;VALUE=DATE:20220606
1524 | DTSTAMP:20230402T151814Z
1525 | UID:20220605_k6v0msnu0286hjb11nbk3t3vac@google.com
1526 | CLASS:PUBLIC
1527 | CREATED:20211209T092338Z
1528 | DESCRIPTION:Gedenktag in Baden-Württemberg\, Bayern\, Berlin\, Brandenburg\
1529 | , Bremen\, Hamburg\, Hessen\, Mecklenburg-Vorpommern\, Niedersachsen\, Nord
1530 | rhein-Westfalen\, Rheinland-Pfalz\, Saarland\, Sachsen\, Sachsen-Anhalt\, S
1531 | chleswig-Holstein\, Thüringen\nWenn Sie Gedenktage ausblenden möchten\, ruf
1532 | en Sie die Google Kalender-Einstellungen auf > Feiertage in Deutschland
1533 | LAST-MODIFIED:20211209T092338Z
1534 | SEQUENCE:0
1535 | STATUS:CONFIRMED
1536 | SUMMARY:Pfingsten (regionaler Feiertag)
1537 | TRANSP:TRANSPARENT
1538 | END:VEVENT
1539 | BEGIN:VEVENT
1540 | DTSTART;VALUE=DATE:20220416
1541 | DTEND;VALUE=DATE:20220417
1542 | DTSTAMP:20230402T151814Z
1543 | UID:20220416_i17s8kvr1puj72m7bu07b53lnc@google.com
1544 | CLASS:PUBLIC
1545 | CREATED:20211016T082227Z
1546 | DESCRIPTION:Gedenktag in Bayern\, Hessen\, Niedersachsen\, Saarland\, Rhein
1547 | land-Pfalz\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie die Google K
1548 | alender-Einstellungen auf > Feiertage in Deutschland
1549 | LAST-MODIFIED:20211016T082227Z
1550 | SEQUENCE:0
1551 | STATUS:CONFIRMED
1552 | SUMMARY:Karsamstag (regionaler Feiertag)
1553 | TRANSP:TRANSPARENT
1554 | END:VEVENT
1555 | BEGIN:VEVENT
1556 | DTSTART;VALUE=DATE:20220501
1557 | DTEND;VALUE=DATE:20220502
1558 | DTSTAMP:20230402T151814Z
1559 | UID:20220501_eu48tsssfu5tehi40h6lc85iac@google.com
1560 | CLASS:PUBLIC
1561 | CREATED:20210826T085007Z
1562 | DESCRIPTION:Gesetzlicher Feiertag
1563 | LAST-MODIFIED:20210826T085007Z
1564 | SEQUENCE:0
1565 | STATUS:CONFIRMED
1566 | SUMMARY:Tag der Arbeit
1567 | TRANSP:TRANSPARENT
1568 | END:VEVENT
1569 | BEGIN:VEVENT
1570 | DTSTART;VALUE=DATE:20220228
1571 | DTEND;VALUE=DATE:20220301
1572 | DTSTAMP:20230402T151814Z
1573 | UID:20220228_np921u7kjge3qq2ge7i9ldr8tk@google.com
1574 | CLASS:PUBLIC
1575 | CREATED:20210826T085007Z
1576 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1577 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1578 | LAST-MODIFIED:20210826T085007Z
1579 | SEQUENCE:0
1580 | STATUS:CONFIRMED
1581 | SUMMARY:Rosenmontag
1582 | TRANSP:TRANSPARENT
1583 | END:VEVENT
1584 | BEGIN:VEVENT
1585 | DTSTART;VALUE=DATE:20220418
1586 | DTEND;VALUE=DATE:20220419
1587 | DTSTAMP:20230402T151814Z
1588 | UID:20220418_g9enfpb523fcvahs196tof61b0@google.com
1589 | CLASS:PUBLIC
1590 | CREATED:20210826T085007Z
1591 | DESCRIPTION:Gesetzlicher Feiertag
1592 | LAST-MODIFIED:20210826T085007Z
1593 | SEQUENCE:0
1594 | STATUS:CONFIRMED
1595 | SUMMARY:Ostermontag
1596 | TRANSP:TRANSPARENT
1597 | END:VEVENT
1598 | BEGIN:VEVENT
1599 | DTSTART;VALUE=DATE:20220508
1600 | DTEND;VALUE=DATE:20220509
1601 | DTSTAMP:20230402T151814Z
1602 | UID:20220508_prb36mppfa8aigkvg34jo3nuv4@google.com
1603 | CLASS:PUBLIC
1604 | CREATED:20210826T085007Z
1605 | DESCRIPTION:Gedenktag in Berlin\, Brandenburg\, Bremen\, Mecklenburg-Vorpom
1606 | mern\, Thüringen\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie die Go
1607 | ogle Kalender-Einstellungen auf > Feiertage in Deutschland
1608 | LAST-MODIFIED:20210826T085007Z
1609 | SEQUENCE:0
1610 | STATUS:CONFIRMED
1611 | SUMMARY:Jahrestag der Befreiung vom Nationalsozialismus (regionaler Feierta
1612 | g)
1613 | TRANSP:TRANSPARENT
1614 | END:VEVENT
1615 | BEGIN:VEVENT
1616 | DTSTART;VALUE=DATE:20220302
1617 | DTEND;VALUE=DATE:20220303
1618 | DTSTAMP:20230402T151814Z
1619 | UID:20220302_5geim1otv341pqji04ti1v311g@google.com
1620 | CLASS:PUBLIC
1621 | CREATED:20210826T085007Z
1622 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1623 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1624 | LAST-MODIFIED:20210826T085007Z
1625 | SEQUENCE:0
1626 | STATUS:CONFIRMED
1627 | SUMMARY:Aschermittwoch
1628 | TRANSP:TRANSPARENT
1629 | END:VEVENT
1630 | BEGIN:VEVENT
1631 | DTSTART;VALUE=DATE:20220920
1632 | DTEND;VALUE=DATE:20220921
1633 | DTSTAMP:20230402T151814Z
1634 | UID:20220920_hutpm9407m7go9qe4detn58la0@google.com
1635 | CLASS:PUBLIC
1636 | CREATED:20210826T085002Z
1637 | DESCRIPTION:Feiertag in Thüringen
1638 | LAST-MODIFIED:20210826T085002Z
1639 | SEQUENCE:0
1640 | STATUS:CONFIRMED
1641 | SUMMARY:Weltkindertag (Thüringen)
1642 | TRANSP:TRANSPARENT
1643 | END:VEVENT
1644 | BEGIN:VEVENT
1645 | DTSTART;VALUE=DATE:20220101
1646 | DTEND;VALUE=DATE:20220102
1647 | DTSTAMP:20230402T151814Z
1648 | UID:20220101_3clq7pqonjkib0ceduk1k42mig@google.com
1649 | CLASS:PUBLIC
1650 | CREATED:20210826T085002Z
1651 | DESCRIPTION:Gesetzlicher Feiertag
1652 | LAST-MODIFIED:20210826T085002Z
1653 | SEQUENCE:0
1654 | STATUS:CONFIRMED
1655 | SUMMARY:Neujahrstag
1656 | TRANSP:TRANSPARENT
1657 | END:VEVENT
1658 | BEGIN:VEVENT
1659 | DTSTART;VALUE=DATE:20220414
1660 | DTEND;VALUE=DATE:20220415
1661 | DTSTAMP:20230402T151814Z
1662 | UID:20220414_pe3ci22d3mirih7569437mkhsc@google.com
1663 | CLASS:PUBLIC
1664 | CREATED:20210826T085002Z
1665 | DESCRIPTION:Gedenktag in Baden-Württemberg\, Bayern\, Berlin\, Brandenburg\
1666 | , Bremen\, Hamburg\, Hessen\, Mecklenburg-Vorpommern\, Niedersachsen\, Nord
1667 | rhein-Westfalen\, Rheinland-Pfalz\, Saarland\, Sachsen\, Sachsen-Anhalt\, S
1668 | chleswig-Holstein\, Thüringen\nWenn Sie Gedenktage ausblenden möchten\, ruf
1669 | en Sie die Google Kalender-Einstellungen auf > Feiertage in Deutschland
1670 | LAST-MODIFIED:20210826T085002Z
1671 | SEQUENCE:0
1672 | STATUS:CONFIRMED
1673 | SUMMARY:Gründonnerstag (regionaler Feiertag)
1674 | TRANSP:TRANSPARENT
1675 | END:VEVENT
1676 | BEGIN:VEVENT
1677 | DTSTART;VALUE=DATE:20220214
1678 | DTEND;VALUE=DATE:20220215
1679 | DTSTAMP:20230402T151814Z
1680 | UID:20220214_v7bgvbvh19koet56qf5md5et10@google.com
1681 | CLASS:PUBLIC
1682 | CREATED:20210826T085000Z
1683 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1684 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1685 | LAST-MODIFIED:20210826T085000Z
1686 | SEQUENCE:0
1687 | STATUS:CONFIRMED
1688 | SUMMARY:Valentinstag
1689 | TRANSP:TRANSPARENT
1690 | END:VEVENT
1691 | BEGIN:VEVENT
1692 | DTSTART;VALUE=DATE:20220606
1693 | DTEND;VALUE=DATE:20220607
1694 | DTSTAMP:20230402T151814Z
1695 | UID:20220606_5vko40qah6gn7tvarguvpub3b4@google.com
1696 | CLASS:PUBLIC
1697 | CREATED:20210826T085000Z
1698 | DESCRIPTION:Gesetzlicher Feiertag
1699 | LAST-MODIFIED:20210826T085000Z
1700 | SEQUENCE:0
1701 | STATUS:CONFIRMED
1702 | SUMMARY:Pfingstmontag
1703 | TRANSP:TRANSPARENT
1704 | END:VEVENT
1705 | BEGIN:VEVENT
1706 | DTSTART;VALUE=DATE:20220106
1707 | DTEND;VALUE=DATE:20220107
1708 | DTSTAMP:20230402T151814Z
1709 | UID:20220106_c55q37enptungumpq3lcasqrqc@google.com
1710 | CLASS:PUBLIC
1711 | CREATED:20210826T085000Z
1712 | DESCRIPTION:Feiertag in Baden-Württemberg\, Bayern\, Sachsen-Anhalt
1713 | LAST-MODIFIED:20210826T085000Z
1714 | SEQUENCE:0
1715 | STATUS:CONFIRMED
1716 | SUMMARY:Heilige Drei Könige (regionaler Feiertag)
1717 | TRANSP:TRANSPARENT
1718 | END:VEVENT
1719 | BEGIN:VEVENT
1720 | DTSTART;VALUE=DATE:20220301
1721 | DTEND;VALUE=DATE:20220302
1722 | DTSTAMP:20230402T151814Z
1723 | UID:20220301_qfrp9i0a2i6a1grvr2ittqpc5s@google.com
1724 | CLASS:PUBLIC
1725 | CREATED:20210826T084959Z
1726 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1727 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1728 | LAST-MODIFIED:20210826T084959Z
1729 | SEQUENCE:0
1730 | STATUS:CONFIRMED
1731 | SUMMARY:Faschingsdienstag
1732 | TRANSP:TRANSPARENT
1733 | END:VEVENT
1734 | BEGIN:VEVENT
1735 | DTSTART;VALUE=DATE:20220308
1736 | DTEND;VALUE=DATE:20220309
1737 | DTSTAMP:20230402T151814Z
1738 | UID:20220308_75egi9afshagblhdssau5kvv0k@google.com
1739 | CLASS:PUBLIC
1740 | CREATED:20210826T084957Z
1741 | DESCRIPTION:Gedenktag in Baden-Württemberg\, Bayern\, Berlin\, Brandenburg\
1742 | , Bremen\, Hamburg\, Hessen\, Mecklenburg-Vorpommern\, Niedersachsen\, Nord
1743 | rhein-Westfalen\, Rheinland-Pfalz\, Saarland\, Sachsen\, Sachsen-Anhalt\, S
1744 | chleswig-Holstein\, Thüringen\nWenn Sie Gedenktage ausblenden möchten\, ruf
1745 | en Sie die Google Kalender-Einstellungen auf > Feiertage in Deutschland
1746 | LAST-MODIFIED:20210826T084957Z
1747 | SEQUENCE:0
1748 | STATUS:CONFIRMED
1749 | SUMMARY:Internationaler Frauentag (regionaler Feiertag)
1750 | TRANSP:TRANSPARENT
1751 | END:VEVENT
1752 | BEGIN:VEVENT
1753 | DTSTART;VALUE=DATE:20220808
1754 | DTEND;VALUE=DATE:20220809
1755 | DTSTAMP:20230402T151814Z
1756 | UID:20220808_n3p0d0sind35e2dj9bl94ccirg@google.com
1757 | CLASS:PUBLIC
1758 | CREATED:20210826T084957Z
1759 | DESCRIPTION:Feiertag in Bayern
1760 | LAST-MODIFIED:20210826T084957Z
1761 | SEQUENCE:0
1762 | STATUS:CONFIRMED
1763 | SUMMARY:Hohes Friedensfest Augsburg (Bayern)
1764 | TRANSP:TRANSPARENT
1765 | END:VEVENT
1766 | BEGIN:VEVENT
1767 | DTSTART;VALUE=DATE:20220410
1768 | DTEND;VALUE=DATE:20220411
1769 | DTSTAMP:20230402T151814Z
1770 | UID:20220410_ep77m78phes9s0d95ejo605mlc@google.com
1771 | CLASS:PUBLIC
1772 | CREATED:20210826T084956Z
1773 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1774 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1775 | LAST-MODIFIED:20210826T084956Z
1776 | SEQUENCE:0
1777 | STATUS:CONFIRMED
1778 | SUMMARY:Palmsonntag
1779 | TRANSP:TRANSPARENT
1780 | END:VEVENT
1781 | BEGIN:VEVENT
1782 | DTSTART;VALUE=DATE:20220508
1783 | DTEND;VALUE=DATE:20220509
1784 | DTSTAMP:20230402T151814Z
1785 | UID:20220508_jqngthi1e7k3jqrk4cffbhc08c@google.com
1786 | CLASS:PUBLIC
1787 | CREATED:20210826T084956Z
1788 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1789 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1790 | LAST-MODIFIED:20210826T084956Z
1791 | SEQUENCE:0
1792 | STATUS:CONFIRMED
1793 | SUMMARY:Muttertag
1794 | TRANSP:TRANSPARENT
1795 | END:VEVENT
1796 | BEGIN:VEVENT
1797 | DTSTART;VALUE=DATE:20220616
1798 | DTEND;VALUE=DATE:20220617
1799 | DTSTAMP:20230402T151814Z
1800 | UID:20220616_gj0en6peukldc4b466t8ru00go@google.com
1801 | CLASS:PUBLIC
1802 | CREATED:20210826T084956Z
1803 | DESCRIPTION:Feiertag in Baden-Württemberg\, Bayern\, Hessen\, Nordrhein-Wes
1804 | tfalen\, Rheinland-Pfalz\, Saarland\, Sachsen\, Thüringen
1805 | LAST-MODIFIED:20210826T084956Z
1806 | SEQUENCE:0
1807 | STATUS:CONFIRMED
1808 | SUMMARY:Fronleichnam (regionaler Feiertag)
1809 | TRANSP:TRANSPARENT
1810 | END:VEVENT
1811 | BEGIN:VEVENT
1812 | DTSTART;VALUE=DATE:20220526
1813 | DTEND;VALUE=DATE:20220527
1814 | DTSTAMP:20230402T151814Z
1815 | UID:20220526_jgrejg15bkvh7o77rvtht2o99k@google.com
1816 | CLASS:PUBLIC
1817 | CREATED:20210826T084956Z
1818 | DESCRIPTION:Gesetzlicher Feiertag
1819 | LAST-MODIFIED:20210826T084956Z
1820 | SEQUENCE:0
1821 | STATUS:CONFIRMED
1822 | SUMMARY:Christi Himmelfahrt
1823 | TRANSP:TRANSPARENT
1824 | END:VEVENT
1825 | BEGIN:VEVENT
1826 | DTSTART;VALUE=DATE:20220526
1827 | DTEND;VALUE=DATE:20220527
1828 | DTSTAMP:20230402T151814Z
1829 | UID:20220526_the2dc156sbh0rfbj1rsn749ts@google.com
1830 | CLASS:PUBLIC
1831 | CREATED:20210826T084954Z
1832 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1833 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1834 | LAST-MODIFIED:20210826T084954Z
1835 | SEQUENCE:0
1836 | STATUS:CONFIRMED
1837 | SUMMARY:Vatertag
1838 | TRANSP:TRANSPARENT
1839 | END:VEVENT
1840 | BEGIN:VEVENT
1841 | DTSTART;VALUE=DATE:20220415
1842 | DTEND;VALUE=DATE:20220416
1843 | DTSTAMP:20230402T151814Z
1844 | UID:20220415_045b5kikdi35u1qk1ohc85miv8@google.com
1845 | CLASS:PUBLIC
1846 | CREATED:20210826T084954Z
1847 | DESCRIPTION:Gesetzlicher Feiertag
1848 | LAST-MODIFIED:20210826T084954Z
1849 | SEQUENCE:0
1850 | STATUS:CONFIRMED
1851 | SUMMARY:Karfreitag
1852 | TRANSP:TRANSPARENT
1853 | END:VEVENT
1854 | BEGIN:VEVENT
1855 | DTSTART;VALUE=DATE:20220327
1856 | DTEND;VALUE=DATE:20220328
1857 | DTSTAMP:20230402T151814Z
1858 | UID:20220327_ps0ir3hjl1vsqtv5rf11fokiuk@google.com
1859 | CLASS:PUBLIC
1860 | CREATED:20210826T084953Z
1861 | DESCRIPTION:Gedenktag\nWenn Sie Gedenktage ausblenden möchten\, rufen Sie d
1862 | ie Google Kalender-Einstellungen auf > Feiertage in Deutschland
1863 | LAST-MODIFIED:20210826T084953Z
1864 | SEQUENCE:0
1865 | STATUS:CONFIRMED
1866 | SUMMARY:Beginn der Sommerzeit
1867 | TRANSP:TRANSPARENT
1868 | END:VEVENT
1869 | END:VCALENDAR
1870 |
--------------------------------------------------------------------------------
/gocalendar/data/hybrid.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/gocalendar/data/names.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/gocalendar/gocalendar.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014 Stefan Schroeder, NY, 2014-04-13
2 | //
3 | // Use of this source code is governed by a BSD-style
4 | // license that can be found in the LICENSE file
5 |
6 | package main
7 |
8 | import (
9 | "flag"
10 | "fmt"
11 | "github.com/StefanSchroeder/Gocal"
12 | "os"
13 | "strconv"
14 | "time"
15 | )
16 |
17 | type arrayFlags []string
18 |
19 | func (i *arrayFlags) String() string {
20 | return "my string representation"
21 | }
22 |
23 | func (i *arrayFlags) Set(value string) error {
24 | *i = append(*i, value)
25 | return nil
26 | }
27 |
28 | // A list of options on the cmdline for configuration
29 | var configFiles arrayFlags
30 |
31 | // A list of options on the cmdline for ICS events
32 | var icsFiles arrayFlags
33 |
34 | const VERSION = "0.9 the Unready"
35 |
36 | var optFont = flag.String("font", "serif", "Font")
37 | var optFontScale = flag.Float64("fontscale", 1.0, "Font")
38 | var optYearSpread = flag.Int("spread", 1, "Spread year over multiple pages")
39 | var optFooter = flag.String("footer", "Gocal", "Footer note")
40 | var optHideDOY = flag.Bool("nodoy", false, "Hide day of year (false)")
41 | var optPlain = flag.Bool("plain", false, "Hide everything")
42 | var optHideEvents = flag.Bool("noevents", false, "Hide events from config file (false)")
43 | var optHideMoon = flag.Bool("nomoon", false, "Hide moon phases (false)")
44 | var optHideWeek = flag.Bool("noweek", false, "Hide week number (false)")
45 | var optLocale = flag.String("lang", "", "Language")
46 | var optOrientation = flag.String("p", "P", "Orientation (L)andscape/(P)ortrait")
47 | var optPaper = flag.String("paper", "A4", "Paper format (A3 A4 A5 Letter Legal)")
48 | var optPhoto = flag.String("photo", "", "Show photo (single image PNG JPG GIF)")
49 | var optPhotos = flag.String("photos", "", "Show photos (directory PNG JPG GIF)")
50 | var optWallpaper = flag.String("wall", "", "Show wallpaper PNG JPG GIF")
51 | var outfilename = flag.String("o", "output.pdf", "Output filename")
52 | var optSmall = flag.Bool("small", false, "Smaller fonts")
53 | var optHideOtherMonths = flag.Bool("noother", false, "Hide neighboring month days")
54 | var optNocolor = flag.Bool("nocolor", false, "Sundays and Saturdays in black, instead of red.")
55 | var optYearA = flag.Bool("yearA", false, "Year calendar (design A)")
56 | var optYearB = flag.Bool("yearB", false, "Year calendar (design B)")
57 | var optFillpattern = flag.String("fill", "", "Set grid fill pattern.")
58 | var optVersion = flag.Bool("v", false, "Version.")
59 | var optMargin = flag.String("margin", "", "Margin comment")
60 |
61 | func main() {
62 | flag.Var(&configFiles, "config", "Configuration XML files.")
63 | flag.Var(&icsFiles, "ics", "Calendar ICS files.")
64 | flag.Parse()
65 |
66 | if *optVersion {
67 | fmt.Printf("# Gocal version %s\n", VERSION)
68 | os.Exit(0)
69 | }
70 |
71 | wantyear := int(time.Now().Year())
72 | beginmonth := 1
73 | endmonth := 12
74 |
75 | if flag.NArg() == 1 {
76 | dummyyear, _ := strconv.ParseInt(flag.Arg(0), 10, 32)
77 | wantyear = int(dummyyear)
78 | } else if flag.NArg() == 2 {
79 | dummymonth, _ := strconv.ParseInt(flag.Arg(0), 10, 32)
80 | dummyyear, _ := strconv.ParseInt(flag.Arg(1), 10, 32)
81 | beginmonth = int(dummymonth)
82 | endmonth = int(dummymonth)
83 | wantyear = int(dummyyear)
84 | } else if flag.NArg() == 3 {
85 | dummymonthBegin, _ := strconv.ParseInt(flag.Arg(0), 10, 32)
86 | dummymonthEnd, _ := strconv.ParseInt(flag.Arg(1), 10, 32)
87 | dummyyear, _ := strconv.ParseInt(flag.Arg(2), 10, 32)
88 | beginmonth = int(dummymonthBegin)
89 | endmonth = int(dummymonthEnd)
90 | wantyear = int(dummyyear)
91 | }
92 |
93 | g := gocal.New(beginmonth, endmonth, wantyear)
94 | g.SetFont(*optFont)
95 | g.SetOrientation(*optOrientation)
96 | g.SetPaperformat(*optPaper)
97 | g.SetLocale(*optLocale)
98 | g.SetYearSpread(*optYearSpread)
99 | if *optYearSpread != 1 && (!*optYearA && !*optYearB) {
100 | fmt.Printf("WARN: Option 'spread' ignored. Only valid for year-mode.\n")
101 | }
102 |
103 | for _, i := range icsFiles {
104 | g.AddICS(i)
105 | }
106 | for _, i := range configFiles {
107 | g.AddConfig(i)
108 | }
109 | if *optPlain == true {
110 | g.SetPlain()
111 | }
112 | if *optHideDOY == true {
113 | g.SetHideDOY()
114 | }
115 | if *optHideWeek == true {
116 | g.SetHideWeek()
117 | }
118 | if *optHideMoon == true {
119 | g.SetHideMoon()
120 | }
121 | if *optSmall == true {
122 | g.SetSmall()
123 | }
124 | if *optNocolor == true {
125 | g.SetNocolor()
126 | }
127 | if *optHideOtherMonths == true {
128 | g.SetHideOtherMonth()
129 | }
130 | g.SetFontScale(*optFontScale)
131 | g.SetWallpaper(*optWallpaper)
132 | g.SetPhotos(*optPhotos)
133 | g.SetPhoto(*optPhoto)
134 | g.SetFooter(*optFooter)
135 | g.SetMargin(*optMargin)
136 | g.SetFillpattern(*optFillpattern)
137 | /*
138 | // How to create an event:
139 | g.AddEvent(31, 1, "one", "")
140 | g.AddEvent(28, 2, "two", "")
141 | g.AddEvent(31, 3, "three", "")
142 | */
143 | if *optYearA == true {
144 | g.CreateYearCalendar(*outfilename)
145 | } else if *optYearB == true {
146 | g.CreateYearCalendarInverse(*outfilename)
147 | } else {
148 | g.CreateCalendar(*outfilename)
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/gocalendar/pics/cooper.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/gocalendar/pics/cooper.jpg
--------------------------------------------------------------------------------
/gocalendar/pics/eddi.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/gocalendar/pics/eddi.JPG
--------------------------------------------------------------------------------
/gocalendar/pics/golang-gopher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/gocalendar/pics/golang-gopher.png
--------------------------------------------------------------------------------
/gocalendar/pics/mayflower.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/gocalendar/pics/mayflower.JPG
--------------------------------------------------------------------------------
/gocalendar/pics/taxi.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/gocalendar/pics/taxi.JPG
--------------------------------------------------------------------------------
/gocalendar/pics/wampanoag.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/gocalendar/pics/wampanoag.JPG
--------------------------------------------------------------------------------
/gocalendar/sample.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | C="pdftoppm "
3 | F="convert -antialias -bordercolor SkyBlue -border 4x4 "
4 | E="go run gocalendar.go"
5 | D=../examples
6 | FONT=data/Borel-Regular.ttf
7 |
8 | $E -o example01.pdf -p P -photos pics 1 2014
9 | $C example01.pdf > example01.ppm
10 | $F example01.ppm $D/example01.png
11 |
12 | $E -o example02.pdf -lang fr_FR -font sans 1 2015
13 | $C example02.pdf > example02.ppm
14 | $F example02.ppm $D/example02.png
15 |
16 | $E -o example03.pdf -wall pics/golang-gopher.png -lang de_DE -font $FONT 1 2015
17 | $C example03.pdf > example03.ppm
18 | $F example03.ppm $D/example03.png
19 |
20 | $E -o example04.pdf -fontscale 0.6 -lang de_DE -font mono 2 2014
21 | $C example04.pdf > example04.ppm
22 | $F example04.ppm $D/example04.png
23 |
24 | $E -o example05.pdf -lang nl_NL -plain 3 2014
25 | $C example05.pdf > example05.ppm
26 | $F example05.ppm $D/example05.png
27 |
28 | $E -o example06.pdf -font $FONT -lang en_US 4 2006
29 | $C example06.pdf > example06.ppm
30 | $F example06.ppm $D/example06.png
31 |
32 | $E -o example07.pdf -p P -lang fr_FR -photo pics/taxi.JPG 4 2007
33 | $C example07.pdf > example07.ppm
34 | $F example07.ppm $D/example07.png
35 |
36 | $E -o example08.pdf -lang fr_FR -photo pics/golang-gopher.png 4 2008
37 | $C example08.pdf > example08.ppm
38 | $F example08.ppm $D/example08.png
39 |
40 | $E -o example09.pdf -lang fi_FI -font serif -p L 4 2009
41 | $C example09.pdf > example09.ppm
42 | $F example09.ppm $D/example09.png
43 |
44 | $E -o example10.pdf -lang fi_FI -font mono -p L 12 2010
45 | $C example10.pdf > example10.ppm
46 | $F example10.ppm $D/example10.png
47 |
48 | $E -o example11.pdf -lang de_DE -font sans -p L 6 2011
49 | $C example11.pdf > example11.ppm
50 | $F example11.ppm $D/example11.png
51 |
52 | $E -o example12.pdf -p P -photo http://golang.org/doc/gopher/frontpage.png 7 2012
53 | $C example12.pdf > example12.ppm
54 | $F example12.ppm $D/example12.png
55 |
56 | $E -o example13.pdf -fontscale 0.9 -font sans -noother 7 2013
57 | $C example13.pdf > example13.ppm
58 | $F example13.ppm $D/example13.png
59 |
60 | $E -o example14.pdf -small 2 2014
61 | $C example14.pdf > example14.ppm
62 | $F example14.ppm $D/example14.png
63 |
64 | $E -o example15.pdf -yearA 2015
65 | $C example15.pdf > example15.ppm
66 | $F example15.ppm $D/example15.png
67 |
68 | $E -o example16.pdf -yearB -p L 2016
69 | $C example16.pdf > example16.ppm
70 | $F example16.ppm $D/example16.png
71 |
72 | $E -o example17.pdf -yearA -fill c 2017
73 | $C example17.pdf > example17.ppm
74 | $F example17.ppm $D/example17.png
75 |
76 | $E -o example18.pdf -yearB -fill sS 2018
77 | $C example18.pdf > example18.ppm
78 | $F example18.ppm $D/example18.png
79 |
80 | $E -o example19.pdf -ics data/german.ics 12 2023
81 | $C example19.pdf > example19.ppm
82 | $F example19.ppm $D/example19.png
83 |
84 | rm example*.ppm example*.pdf
85 |
86 |
--------------------------------------------------------------------------------
/golang-gopher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/StefanSchroeder/Gocal/65c0f13d3776fc3da2cfa5ded0b25426526b4c48/golang-gopher.png
--------------------------------------------------------------------------------
/test-gocal.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/util.go:
--------------------------------------------------------------------------------
1 | package gocal
2 |
3 | // Copyright (c) 2014 Stefan Schroeder, NY, 2014-03-10
4 | //
5 | // Use of this source code is governed by a BSD-style
6 | // license that can be found in the LICENSE file
7 | //
8 | // util.go
9 | //
10 | // This file is part of gocal, a PDF calendar generator in Go.
11 | //
12 | // https://github.com/StefanSchroeder/Gocal
13 | //
14 |
15 | import _ "embed"
16 |
17 |
18 | import (
19 | "bytes"
20 | "encoding/xml"
21 | "fmt"
22 | "github.com/PuloV/ics-golang"
23 | "github.com/goodsign/monday"
24 | "github.com/jung-kurt/gofpdf"
25 | "github.com/paulrosania/go-charset/charset"
26 | _ "github.com/paulrosania/go-charset/data"
27 | "github.com/soniakeys/meeus/v3/julian"
28 | "github.com/soniakeys/meeus/v3/moonphase"
29 | "io"
30 | "io/ioutil"
31 | "log"
32 | "net/http"
33 | "os"
34 | "path/filepath"
35 | "strconv"
36 | "strings"
37 | "time"
38 | )
39 |
40 | const YmdHis = "2006-01-02 15:04:05"
41 |
42 | // TelegramStore is a container to read XML event-list
43 | type TelegramStore struct {
44 | XMLName xml.Name `xml:"Gocal"`
45 | Gocaldate []Gocaldate
46 | }
47 |
48 | const (
49 | CLEARTEMP = true
50 | )
51 |
52 | // removeTempdir removes the temoprary directory,
53 | // unless we want to keep it for debugging.
54 | func removeTempdir(d string) {
55 | if CLEARTEMP == false {
56 | return
57 | }
58 | os.RemoveAll(d)
59 | }
60 |
61 | // computeMoonphasesJ populates a map for the entire year.
62 | // Keys are dates in YYYY-MM-DD format,
63 | // Values are strings from the list Full, New, First, Last.
64 | func computeMoonphasesJ(moonJ map[string]string, yr int) {
65 | daysInYear := 365
66 | if julian.LeapYearGregorian(yr) {
67 | daysInYear = 366
68 | }
69 |
70 | moon_funcs := map[string]func(float64) float64{
71 | "Full": moonphase.Full,
72 | "New": moonphase.New,
73 | "First": moonphase.First,
74 | "Last": moonphase.Last,
75 | }
76 |
77 | // For each days of the year we compute the
78 | // nearest Full/New/First/Last moonphase.
79 | // The dates for each are crammed into the result map.
80 | for i := 0; i < daysInYear; i++ {
81 | decimalYear := float64(yr) +
82 | float64(i-1)/float64(daysInYear)
83 | for moonkey, _ := range moon_funcs {
84 | jd := moon_funcs[moonkey](decimalYear)
85 | y, m, d := julian.JDToCalendar(jd)
86 | moonString := fmt.Sprintf("%04d-%02d-%02d", y, m, int(d))
87 | moonJ[moonString] = moonkey
88 | }
89 | }
90 | }
91 |
92 | // computeMoonphases fills a map with moonphase information.
93 | func computeMoonphases(moon map[int]string, da int, mo int, yr int) {
94 | daysInYear := 365
95 | if julian.LeapYearGregorian(yr) {
96 | daysInYear = 366
97 | }
98 | // Look at every day and check if it has any of the Moon Phases.
99 | for i := 0; i < 32; i++ {
100 | dayOfYear := julian.DayOfYearGregorian(yr, mo, int(da)+i)
101 | decimalYear := float64(yr) +
102 | float64(dayOfYear-1)/float64(daysInYear)
103 | jdeNew := moonphase.New(decimalYear)
104 | y, m, d := julian.JDToCalendar(jdeNew)
105 | if (y == yr) && (m == mo) && (int(d) == i) {
106 | fmt.Printf("New moon on %d.%d.%d\n", int(d), int(m), int(y))
107 | moon[int(d)] = "New"
108 | }
109 | jdeNew = moonphase.Full(decimalYear)
110 | y, m, d = julian.JDToCalendar(jdeNew)
111 | if (y == yr) && (m == mo) && (int(d) == i) {
112 | fmt.Printf("Full moon on %d.%d.%d\n", int(d), int(m), int(y))
113 | moon[int(d)] = "Full"
114 | }
115 | jdeNew = moonphase.First(decimalYear)
116 | y, m, d = julian.JDToCalendar(jdeNew)
117 | if (y == yr) && (m == mo) && (int(d) == i) {
118 | //fmt.Printf("First Q moon on %d\n", int(d))
119 | moon[int(d)] = "First"
120 | }
121 | jdeNew = moonphase.Last(decimalYear)
122 | y, m, d = julian.JDToCalendar(jdeNew)
123 | if (y == yr) && (m == mo) && (int(d) == i) {
124 | moon[int(d)] = "Last"
125 | //fmt.Printf("Last Q moon on %d\n", int(d))
126 | }
127 | }
128 | }
129 |
130 | //go:embed fonts/FreeSansBold.ttf
131 | var freesansbold []byte
132 |
133 | //go:embed fonts/FreeMonoBold.ttf
134 | var freemonobold []byte
135 |
136 | //go:embed fonts/FreeSerifBold.ttf
137 | var freeserifbold []byte
138 |
139 | // processFont creates a font usable from a TTF.
140 | // It also sets up the temporary directory to store the
141 | // intermediate files.
142 | func processFont(fontFile string) (fontName, tempDirname string) {
143 | var err error
144 | tempDirname, err = ioutil.TempDir("", "")
145 | if err != nil {
146 | log.Fatal(err)
147 | }
148 |
149 | if fontFile == "mono" {
150 | fontFile = tempDirname + string(os.PathSeparator) + "freemonobold.ttf"
151 | ioutil.WriteFile(fontFile, freemonobold, 0700)
152 | } else if fontFile == "serif" {
153 | fontFile = tempDirname + string(os.PathSeparator) + "freeserifbold.ttf"
154 | ioutil.WriteFile(fontFile, freeserifbold, 0700)
155 | } else if fontFile == "sans" {
156 | fontFile = tempDirname + string(os.PathSeparator) + "freesansbold.ttf"
157 | ioutil.WriteFile(fontFile, freesansbold, 0700)
158 | }
159 | err = ioutil.WriteFile(tempDirname+string(os.PathSeparator)+"cp1252.map", []byte(codepageCP1252), 0700)
160 | if err != nil {
161 | log.Fatal(err)
162 | }
163 | err = gofpdf.MakeFont(fontFile, tempDirname+string(os.PathSeparator)+"cp1252.map", tempDirname, nil, true)
164 | if err != nil {
165 | log.Fatal(err)
166 | }
167 | fontName = filepath.Base(fontFile)
168 | fontName = strings.TrimSuffix(fontName, filepath.Ext(fontName))
169 | // fmt.Printf("Using external font: %v\n", fontName)
170 | return fontName, tempDirname
171 | }
172 |
173 | // downloadFile loads a file via http into the tempDir
174 | // and returns the fullpath filename.
175 | func downloadFile(in string, tempDir string) (fileName string) {
176 | extension := filepath.Ext(in)
177 |
178 | // The filename from the URL might contain colons that are
179 | // not valid characters in a filename in Windows. THerefore
180 | // we simply call out image 'image'.
181 | fileName = "image" + extension
182 | fileName = tempDir + string(os.PathSeparator) + fileName
183 |
184 | output, err := os.Create(fileName)
185 | if err != nil {
186 | fmt.Printf("# Error creating %v\n", output)
187 | return
188 | }
189 | defer output.Close()
190 |
191 | retrieve, err := http.Get(in)
192 | if err != nil {
193 | fmt.Printf("# Error downloading %v\n", in)
194 | return
195 | }
196 | defer retrieve.Body.Close()
197 |
198 | _, err = io.Copy(output, retrieve.Body)
199 | if err != nil {
200 | fmt.Printf("# Error copying %v\n", in)
201 | return
202 | }
203 |
204 | return fileName
205 | }
206 |
207 | // This function converts a string into the required
208 | // Codepage.
209 | func convertCP(in string) (out string) {
210 | buf := new(bytes.Buffer)
211 | w, err := charset.NewWriter("windows-1252", buf)
212 | if err != nil {
213 | log.Fatal(err)
214 | }
215 | fmt.Fprintf(w, in)
216 | w.Close()
217 |
218 | out = fmt.Sprintf("%s", buf)
219 | return out
220 | }
221 |
222 | // This function reads the events XML file and returns a
223 | // list of gDate objects.
224 | func readICSfile(filename string, targetyear int) (eL []gDate) {
225 |
226 | /* There is an ugly hack lurking here. The events in ICS
227 | contain years, but we wanted the configuration to be
228 | agnostic of years.*/
229 | parser := ics.New()
230 |
231 | ics.FilePath = "tmp/new/"
232 |
233 | ics.DeleteTempFiles = true
234 |
235 | inputChan := parser.GetInputChan()
236 |
237 | outputChan := parser.GetOutputChan()
238 |
239 | inputChan <- filename
240 |
241 | go func() {
242 | for event := range outputChan {
243 | eventText := convertCP(event.GetSummary())
244 | year := event.GetStart().Format("2006")
245 | mon := event.GetStart().Format("01")
246 | day := event.GetStart().Format("02")
247 |
248 | yr, _ := strconv.ParseInt(year, 10, 32)
249 | mo, _ := strconv.ParseInt(mon, 10, 32)
250 | d, _ := strconv.ParseInt(day, 10, 32)
251 | if int(targetyear) == int(yr) {
252 | gcd := gDate{time.Month(mo), int(d), eventText, "", ""}
253 | eL = append(eL, gcd)
254 | }
255 | }
256 | }()
257 | parser.Wait()
258 |
259 | return eL
260 | }
261 |
262 | // This function reads the events XML file and returns a
263 | // list of gDate objects.
264 | func readConfigurationfile(filename string) (eL []gDate) {
265 |
266 | var v TelegramStore
267 |
268 | f, err := os.Open(filename)
269 | if err != nil {
270 | return
271 | }
272 | defer f.Close()
273 | data, err := ioutil.ReadAll(f)
274 | if err != nil {
275 | return
276 | }
277 |
278 | v = TelegramStore{}
279 | err2 := xml.Unmarshal([]byte(data), &v)
280 | if err2 != nil {
281 | log.Fatalf("# ERROR: when trying to unmarshal the XML configuration file: %v", err2)
282 | return
283 | }
284 |
285 | for _, m := range v.Gocaldate {
286 |
287 | if strings.Index(m.Date, "/") != -1 { // Is this Month/Day ?
288 |
289 | textArray := strings.Split(m.Date, "/")
290 |
291 | eventText := convertCP(m.Text)
292 |
293 | if textArray[0] == "*" {
294 | d, _ := strconv.ParseInt(textArray[1], 10, 32)
295 | for j := 1; j < 13; j++ {
296 | gcd := gDate{time.Month(j), int(d), eventText, "", m.Image}
297 | eL = append(eL, gcd)
298 | }
299 | } else {
300 | mo, _ := strconv.ParseInt(textArray[0], 10, 32)
301 | d, _ := strconv.ParseInt(textArray[1], 10, 32)
302 |
303 | gcd := gDate{time.Month(mo), int(d), eventText, "", m.Image}
304 | eL = append(eL, gcd)
305 | }
306 | } else { // There is no slash, assume weekday
307 |
308 | eventText := convertCP(m.Text)
309 | gcd := gDate{time.Month(0), int(0), eventText, string(m.Date), m.Image}
310 | eL = append(eL, gcd)
311 | }
312 | }
313 |
314 | return eL
315 | }
316 |
317 | // / This function returns an array of Monthnames already in the
318 | // right locale.
319 | func getLocalizedMonthNames(locale string) (monthnames [13]string) {
320 |
321 | for page := 1; page < 13; page++ {
322 | t := time.Date(2013, time.Month(page), 1, 0, 0, 0, 0, time.UTC)
323 | monthnames[page] = convertCP(fmt.Sprintf("%s", monday.Format(t, "January", monday.Locale(locale))))
324 | }
325 |
326 | return monthnames
327 | }
328 |
329 | // / This function returns an array of weekday names already in the
330 | // right locale.
331 | func getLocalizedWeekdayNames(locale string, cutoff int) (wdnames [8]string) {
332 | for i := 0; i <= 6; i++ {
333 | // Some arbitrary date, that allows us to pickup Weekday-Strings.
334 | t := time.Date(2013, 1, 5+i, 0, 0, 0, 0, time.UTC)
335 | wdnames[i] = convertCP(monday.Format(t, "Monday", monday.Locale(locale)))
336 | if cutoff > 0 {
337 | wdnames[i] = wdnames[i][0:cutoff]
338 | }
339 | }
340 | return wdnames
341 | }
342 |
343 | const codepageCP1252 = `!00 U+0000 .notdef
344 | !01 U+0001 .notdef
345 | !02 U+0002 .notdef
346 | !03 U+0003 .notdef
347 | !04 U+0004 .notdef
348 | !05 U+0005 .notdef
349 | !06 U+0006 .notdef
350 | !07 U+0007 .notdef
351 | !08 U+0008 .notdef
352 | !09 U+0009 .notdef
353 | !0A U+000A .notdef
354 | !0B U+000B .notdef
355 | !0C U+000C .notdef
356 | !0D U+000D .notdef
357 | !0E U+000E .notdef
358 | !0F U+000F .notdef
359 | !10 U+0010 .notdef
360 | !11 U+0011 .notdef
361 | !12 U+0012 .notdef
362 | !13 U+0013 .notdef
363 | !14 U+0014 .notdef
364 | !15 U+0015 .notdef
365 | !16 U+0016 .notdef
366 | !17 U+0017 .notdef
367 | !18 U+0018 .notdef
368 | !19 U+0019 .notdef
369 | !1A U+001A .notdef
370 | !1B U+001B .notdef
371 | !1C U+001C .notdef
372 | !1D U+001D .notdef
373 | !1E U+001E .notdef
374 | !1F U+001F .notdef
375 | !20 U+0020 space
376 | !21 U+0021 exclam
377 | !22 U+0022 quotedbl
378 | !23 U+0023 numbersign
379 | !24 U+0024 dollar
380 | !25 U+0025 percent
381 | !26 U+0026 ampersand
382 | !27 U+0027 quotesingle
383 | !28 U+0028 parenleft
384 | !29 U+0029 parenright
385 | !2A U+002A asterisk
386 | !2B U+002B plus
387 | !2C U+002C comma
388 | !2D U+002D hyphen
389 | !2E U+002E period
390 | !2F U+002F slash
391 | !30 U+0030 zero
392 | !31 U+0031 one
393 | !32 U+0032 two
394 | !33 U+0033 three
395 | !34 U+0034 four
396 | !35 U+0035 five
397 | !36 U+0036 six
398 | !37 U+0037 seven
399 | !38 U+0038 eight
400 | !39 U+0039 nine
401 | !3A U+003A colon
402 | !3B U+003B semicolon
403 | !3C U+003C less
404 | !3D U+003D equal
405 | !3E U+003E greater
406 | !3F U+003F question
407 | !40 U+0040 at
408 | !41 U+0041 A
409 | !42 U+0042 B
410 | !43 U+0043 C
411 | !44 U+0044 D
412 | !45 U+0045 E
413 | !46 U+0046 F
414 | !47 U+0047 G
415 | !48 U+0048 H
416 | !49 U+0049 I
417 | !4A U+004A J
418 | !4B U+004B K
419 | !4C U+004C L
420 | !4D U+004D M
421 | !4E U+004E N
422 | !4F U+004F O
423 | !50 U+0050 P
424 | !51 U+0051 Q
425 | !52 U+0052 R
426 | !53 U+0053 S
427 | !54 U+0054 T
428 | !55 U+0055 U
429 | !56 U+0056 V
430 | !57 U+0057 W
431 | !58 U+0058 X
432 | !59 U+0059 Y
433 | !5A U+005A Z
434 | !5B U+005B bracketleft
435 | !5C U+005C backslash
436 | !5D U+005D bracketright
437 | !5E U+005E asciicircum
438 | !5F U+005F underscore
439 | !60 U+0060 grave
440 | !61 U+0061 a
441 | !62 U+0062 b
442 | !63 U+0063 c
443 | !64 U+0064 d
444 | !65 U+0065 e
445 | !66 U+0066 f
446 | !67 U+0067 g
447 | !68 U+0068 h
448 | !69 U+0069 i
449 | !6A U+006A j
450 | !6B U+006B k
451 | !6C U+006C l
452 | !6D U+006D m
453 | !6E U+006E n
454 | !6F U+006F o
455 | !70 U+0070 p
456 | !71 U+0071 q
457 | !72 U+0072 r
458 | !73 U+0073 s
459 | !74 U+0074 t
460 | !75 U+0075 u
461 | !76 U+0076 v
462 | !77 U+0077 w
463 | !78 U+0078 x
464 | !79 U+0079 y
465 | !7A U+007A z
466 | !7B U+007B braceleft
467 | !7C U+007C bar
468 | !7D U+007D braceright
469 | !7E U+007E asciitilde
470 | !7F U+007F .notdef
471 | !80 U+20AC Euro
472 | !82 U+201A quotesinglbase
473 | !83 U+0192 florin
474 | !84 U+201E quotedblbase
475 | !85 U+2026 ellipsis
476 | !86 U+2020 dagger
477 | !87 U+2021 daggerdbl
478 | !88 U+02C6 circumflex
479 | !89 U+2030 perthousand
480 | !8A U+0160 Scaron
481 | !8B U+2039 guilsinglleft
482 | !8C U+0152 OE
483 | !8E U+017D Zcaron
484 | !91 U+2018 quoteleft
485 | !92 U+2019 quoteright
486 | !93 U+201C quotedblleft
487 | !94 U+201D quotedblright
488 | !95 U+2022 bullet
489 | !96 U+2013 endash
490 | !97 U+2014 emdash
491 | !98 U+02DC tilde
492 | !99 U+2122 trademark
493 | !9A U+0161 scaron
494 | !9B U+203A guilsinglright
495 | !9C U+0153 oe
496 | !9E U+017E zcaron
497 | !9F U+0178 Ydieresis
498 | !A0 U+00A0 space
499 | !A1 U+00A1 exclamdown
500 | !A2 U+00A2 cent
501 | !A3 U+00A3 sterling
502 | !A4 U+00A4 currency
503 | !A5 U+00A5 yen
504 | !A6 U+00A6 brokenbar
505 | !A7 U+00A7 section
506 | !A8 U+00A8 dieresis
507 | !A9 U+00A9 copyright
508 | !AA U+00AA ordfeminine
509 | !AB U+00AB guillemotleft
510 | !AC U+00AC logicalnot
511 | !AD U+00AD hyphen
512 | !AE U+00AE registered
513 | !AF U+00AF macron
514 | !B0 U+00B0 degree
515 | !B1 U+00B1 plusminus
516 | !B2 U+00B2 twosuperior
517 | !B3 U+00B3 threesuperior
518 | !B4 U+00B4 acute
519 | !B5 U+00B5 mu
520 | !B6 U+00B6 paragraph
521 | !B7 U+00B7 periodcentered
522 | !B8 U+00B8 cedilla
523 | !B9 U+00B9 onesuperior
524 | !BA U+00BA ordmasculine
525 | !BB U+00BB guillemotright
526 | !BC U+00BC onequarter
527 | !BD U+00BD onehalf
528 | !BE U+00BE threequarters
529 | !BF U+00BF questiondown
530 | !C0 U+00C0 Agrave
531 | !C1 U+00C1 Aacute
532 | !C2 U+00C2 Acircumflex
533 | !C3 U+00C3 Atilde
534 | !C4 U+00C4 Adieresis
535 | !C5 U+00C5 Aring
536 | !C6 U+00C6 AE
537 | !C7 U+00C7 Ccedilla
538 | !C8 U+00C8 Egrave
539 | !C9 U+00C9 Eacute
540 | !CA U+00CA Ecircumflex
541 | !CB U+00CB Edieresis
542 | !CC U+00CC Igrave
543 | !CD U+00CD Iacute
544 | !CE U+00CE Icircumflex
545 | !CF U+00CF Idieresis
546 | !D0 U+00D0 Eth
547 | !D1 U+00D1 Ntilde
548 | !D2 U+00D2 Ograve
549 | !D3 U+00D3 Oacute
550 | !D4 U+00D4 Ocircumflex
551 | !D5 U+00D5 Otilde
552 | !D6 U+00D6 Odieresis
553 | !D7 U+00D7 multiply
554 | !D8 U+00D8 Oslash
555 | !D9 U+00D9 Ugrave
556 | !DA U+00DA Uacute
557 | !DB U+00DB Ucircumflex
558 | !DC U+00DC Udieresis
559 | !DD U+00DD Yacute
560 | !DE U+00DE Thorn
561 | !DF U+00DF germandbls
562 | !E0 U+00E0 agrave
563 | !E1 U+00E1 aacute
564 | !E2 U+00E2 acircumflex
565 | !E3 U+00E3 atilde
566 | !E4 U+00E4 adieresis
567 | !E5 U+00E5 aring
568 | !E6 U+00E6 ae
569 | !E7 U+00E7 ccedilla
570 | !E8 U+00E8 egrave
571 | !E9 U+00E9 eacute
572 | !EA U+00EA ecircumflex
573 | !EB U+00EB edieresis
574 | !EC U+00EC igrave
575 | !ED U+00ED iacute
576 | !EE U+00EE icircumflex
577 | !EF U+00EF idieresis
578 | !F0 U+00F0 eth
579 | !F1 U+00F1 ntilde
580 | !F2 U+00F2 ograve
581 | !F3 U+00F3 oacute
582 | !F4 U+00F4 ocircumflex
583 | !F5 U+00F5 otilde
584 | !F6 U+00F6 odieresis
585 | !F7 U+00F7 divide
586 | !F8 U+00F8 oslash
587 | !F9 U+00F9 ugrave
588 | !FA U+00FA uacute
589 | !FB U+00FB ucircumflex
590 | !FC U+00FC udieresis
591 | !FD U+00FD yacute
592 | !FE U+00FE thorn
593 | !FF U+00FF ydieresis
594 | `
595 |
--------------------------------------------------------------------------------