├── .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 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/01-2025.png?raw=true) 2 | 3 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 4 | [![Go](https://github.com/StefanSchroeder/Gocal/actions/workflows/go.yml/badge.svg)](https://github.com/StefanSchroeder/Gocal/actions/workflows/go.yml) 5 | [![GoDoc](https://godoc.org/github.com/StefanSchroeder/Gocal?status.png)](https://godoc.org/github.com/StefanSchroeder/Gocal) 6 | [![Go Report Card](https://goreportcard.com/badge/github.com/StefanSchroeder/Gocal)](https://goreportcard.com/report/github.com/StefanSchroeder/Gocal) 7 | [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/StefanSchroeder/Gocal/badge)](https://api.securityscorecards.dev/projects/github.com/StefanSchroeder/Gocal) 8 | [![codecov](https://codecov.io/github/StefanSchroeder/Gocal/branch/master/graph/badge.svg?token=SIRJ6HIFJV)](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 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example01.png?raw=true) 394 | 395 | gocalendar -o example01.pdf -p P -photos pics 1 2026 396 | 397 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example02.png?raw=true) 398 | 399 | gocalendar -o example02.pdf -lang fr_FR -font sans 2027 400 | 401 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example03.png?raw=true) 402 | 403 | gocalendar -o example03.pdf -wall golang-gopher.png -lang de_DE -font data/Borel-Regular.ttf 2028 404 | 405 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example04.png?raw=true) 406 | 407 | gocalendar -o example04.pdf -lang de_DE -font mono 2 2029 408 | 409 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example05.png?raw=true) 410 | 411 | gocalendar -o example05.pdf -lang nl_NL -plain 3 2030 412 | 413 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example06.png?raw=true) 414 | 415 | gocalendar -o example06.pdf -font data/Borel-Regular.ttf -lang en_US 4 2031 416 | 417 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example07.png?raw=true) 418 | 419 | gocalendar -o example07.pdf -p P -lang fr_FR -photo pics\taxi.JPG 4 2032 420 | 421 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example08.png?raw=true) 422 | 423 | gocalendar -o example08.pdf -lang fr_FR -photo golang-gopher.png 4 2033 424 | 425 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example09.png?raw=true) 426 | 427 | gocalendar -o example09.pdf -lang fi_FI -font serif -p L 4 2034 428 | 429 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example10.png?raw=true) 430 | 431 | gocalendar -o example10.pdf -lang fi_FI -font serif -p L 12 2035 432 | 433 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example11.png?raw=true) 434 | 435 | gocalendar -o example11.pdf -lang de_DE -font sans -p L 6 9 2036 436 | 437 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example12.png?raw=true) 438 | 439 | gocalendar -o example12.pdf -p P -photo http://golang.org/doc/gopher/frontpage.png 7 2037 440 | 441 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example13.png?raw=true) 442 | 443 | gocalendar -o example13.pdf -font sans -noother 7 2038 444 | 445 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example14.png?raw=true) 446 | 447 | gocalendar -o example14.pdf -small 2 2039 448 | 449 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example15.png?raw=true) 450 | 451 | gocalendar -o example15.pdf -yearA 2040 452 | 453 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example16.png?raw=true) 454 | 455 | gocalendar -o example16.pdf -yearB 2041 456 | 457 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example17.png?raw=true) 458 | 459 | gocalendar -o example17.pdf -yearA -fill "c" 2042 460 | 461 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example18.png?raw=true) 462 | 463 | gocalendar -o example18.pdf -yearB -fill "sS" 2043 464 | 465 | ![Logo](https://github.com/StefanSchroeder/Gocal/blob/master/examples/example19.png?raw=true) 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 | --------------------------------------------------------------------------------