Init
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -1,2 +1,343 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
Console.WriteLine("Hello, World!");
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Org2Ics;
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (args.Length < 1)
|
||||
{
|
||||
Console.WriteLine("Usage: Org2Ics <input.org|input.ics> [output.ics|output.org]");
|
||||
Console.WriteLine("Converts between .org diary files and .ics calendar files.");
|
||||
Console.WriteLine(" - .org to .ics: Converts org diary entries to calendar events");
|
||||
Console.WriteLine(" - .ics to .org: Converts calendar events to org diary format");
|
||||
return;
|
||||
}
|
||||
|
||||
string inputFile = args[0];
|
||||
string inputExt = Path.GetExtension(inputFile).ToLowerInvariant();
|
||||
|
||||
string outputFile;
|
||||
if (args.Length > 1)
|
||||
{
|
||||
outputFile = args[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Auto-determine output format based on input
|
||||
outputFile = inputExt == ".org"
|
||||
? Path.ChangeExtension(inputFile, ".ics")
|
||||
: Path.ChangeExtension(inputFile, ".org");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var converter = new CalendarConverter();
|
||||
|
||||
if (inputExt == ".org")
|
||||
{
|
||||
converter.ConvertOrgToIcs(inputFile, outputFile);
|
||||
}
|
||||
else if (inputExt == ".ics")
|
||||
{
|
||||
converter.ConvertIcsToOrg(inputFile, outputFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Unsupported file format: {inputExt}. Only .org and .ics files are supported.");
|
||||
}
|
||||
|
||||
Console.WriteLine($"Successfully converted {inputFile} to {outputFile}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class CalendarConverter
|
||||
{
|
||||
private readonly Regex _dateHeaderRegex = new(@"^\*{3}\s+(\d{4}-\d{2}-\d{2})\s*$", RegexOptions.Compiled);
|
||||
|
||||
public void ConvertOrgToIcs(string inputFile, string outputFile)
|
||||
{
|
||||
if (!File.Exists(inputFile))
|
||||
throw new FileNotFoundException($"Input file not found: {inputFile}");
|
||||
|
||||
var entries = ParseOrgFile(inputFile);
|
||||
GenerateIcsFile(entries, outputFile);
|
||||
}
|
||||
|
||||
public void ConvertIcsToOrg(string inputFile, string outputFile)
|
||||
{
|
||||
if (!File.Exists(inputFile))
|
||||
throw new FileNotFoundException($"Input file not found: {inputFile}");
|
||||
|
||||
var entries = ParseIcsFile(inputFile);
|
||||
GenerateOrgFile(entries, outputFile);
|
||||
}
|
||||
|
||||
private List<DiaryEntry> ParseOrgFile(string inputFile)
|
||||
{
|
||||
var entries = new List<DiaryEntry>();
|
||||
var lines = File.ReadAllLines(inputFile);
|
||||
|
||||
DiaryEntry? currentEntry = null;
|
||||
var contentBuilder = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
{
|
||||
string line = lines[i];
|
||||
var match = _dateHeaderRegex.Match(line);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
// Save previous entry if exists
|
||||
if (currentEntry != null)
|
||||
{
|
||||
currentEntry.Content = contentBuilder.ToString().Trim();
|
||||
entries.Add(currentEntry);
|
||||
contentBuilder.Clear();
|
||||
}
|
||||
|
||||
// Start new entry
|
||||
if (DateTime.TryParseExact(match.Groups[1].Value, "yyyy-MM-dd",
|
||||
CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date))
|
||||
{
|
||||
currentEntry = new DiaryEntry
|
||||
{
|
||||
Date = date,
|
||||
Content = string.Empty
|
||||
};
|
||||
}
|
||||
}
|
||||
else if (currentEntry != null)
|
||||
{
|
||||
// Check if this is another header that ends the current entry
|
||||
if (line.StartsWith("*"))
|
||||
{
|
||||
// This is another header, save current entry and reset
|
||||
currentEntry.Content = contentBuilder.ToString().Trim();
|
||||
entries.Add(currentEntry);
|
||||
currentEntry = null;
|
||||
contentBuilder.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add content to current entry
|
||||
contentBuilder.AppendLine(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save the last entry if exists
|
||||
if (currentEntry != null)
|
||||
{
|
||||
currentEntry.Content = contentBuilder.ToString().Trim();
|
||||
entries.Add(currentEntry);
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private void GenerateIcsFile(List<DiaryEntry> entries, string outputFile)
|
||||
{
|
||||
var icsBuilder = new StringBuilder();
|
||||
|
||||
// ICS header
|
||||
icsBuilder.AppendLine("BEGIN:VCALENDAR");
|
||||
icsBuilder.AppendLine("VERSION:2.0");
|
||||
icsBuilder.AppendLine("PRODID:-//Org2Ics//Org2Ics//EN");
|
||||
icsBuilder.AppendLine("CALSCALE:GREGORIAN");
|
||||
icsBuilder.AppendLine("METHOD:PUBLISH");
|
||||
|
||||
// Generate events
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
GenerateEvent(icsBuilder, entry);
|
||||
}
|
||||
|
||||
// ICS footer
|
||||
icsBuilder.AppendLine("END:VCALENDAR");
|
||||
|
||||
File.WriteAllText(outputFile, icsBuilder.ToString(), Encoding.UTF8);
|
||||
}
|
||||
|
||||
private void GenerateEvent(StringBuilder icsBuilder, DiaryEntry entry)
|
||||
{
|
||||
string uid = $"chronolog-{entry.Date:yyyy-MM-dd}@org2ics";
|
||||
string dateStamp = DateTime.UtcNow.ToString("yyyyMMddTHHmmssZ");
|
||||
string eventDate = entry.Date.ToString("yyyyMMdd");
|
||||
|
||||
icsBuilder.AppendLine("BEGIN:VEVENT");
|
||||
icsBuilder.AppendLine($"UID:{uid}");
|
||||
icsBuilder.AppendLine($"DTSTAMP:{dateStamp}");
|
||||
icsBuilder.AppendLine($"DTSTART;VALUE=DATE:{eventDate}");
|
||||
icsBuilder.AppendLine($"DTEND;VALUE=DATE:{entry.Date.AddDays(1):yyyyMMdd}");
|
||||
icsBuilder.AppendLine("SUMMARY:Chronolog");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(entry.Content))
|
||||
{
|
||||
// Escape special characters in description
|
||||
string description = EscapeIcsText(entry.Content);
|
||||
icsBuilder.AppendLine($"DESCRIPTION:{description}");
|
||||
}
|
||||
|
||||
icsBuilder.AppendLine("END:VEVENT");
|
||||
}
|
||||
|
||||
private string EscapeIcsText(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return string.Empty;
|
||||
|
||||
// Replace line breaks and escape special characters according to RFC 5545
|
||||
return text
|
||||
.Replace("\\", "\\\\")
|
||||
.Replace(",", "\\,")
|
||||
.Replace(";", "\\;")
|
||||
.Replace("\r\n", "\\n")
|
||||
.Replace("\n", "\\n")
|
||||
.Replace("\r", "\\n");
|
||||
}
|
||||
|
||||
private List<DiaryEntry> ParseIcsFile(string inputFile)
|
||||
{
|
||||
var entries = new List<DiaryEntry>();
|
||||
var lines = File.ReadAllLines(inputFile);
|
||||
|
||||
bool inEvent = false;
|
||||
DiaryEntry? currentEntry = null;
|
||||
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
{
|
||||
string line = lines[i].Trim();
|
||||
|
||||
if (line == "BEGIN:VEVENT")
|
||||
{
|
||||
inEvent = true;
|
||||
currentEntry = new DiaryEntry();
|
||||
}
|
||||
else if (line == "END:VEVENT" && inEvent && currentEntry != null)
|
||||
{
|
||||
if (currentEntry.Date != default &&
|
||||
(string.IsNullOrEmpty(currentEntry.Content) || currentEntry.Content != "Unknown Event"))
|
||||
{
|
||||
entries.Add(currentEntry);
|
||||
}
|
||||
inEvent = false;
|
||||
currentEntry = null;
|
||||
}
|
||||
else if (inEvent && currentEntry != null)
|
||||
{
|
||||
if (line.StartsWith("DTSTART;VALUE=DATE:"))
|
||||
{
|
||||
string dateStr = line.Substring("DTSTART;VALUE=DATE:".Length);
|
||||
if (DateTime.TryParseExact(dateStr, "yyyyMMdd",
|
||||
CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date))
|
||||
{
|
||||
currentEntry.Date = date;
|
||||
}
|
||||
}
|
||||
else if (line.StartsWith("DTSTART:"))
|
||||
{
|
||||
// Handle datetime format YYYYMMDDTHHMMSSZ
|
||||
string dateTimeStr = line.Substring("DTSTART:".Length);
|
||||
if (dateTimeStr.Contains("T"))
|
||||
{
|
||||
string dateStr = dateTimeStr.Substring(0, 8);
|
||||
if (DateTime.TryParseExact(dateStr, "yyyyMMdd",
|
||||
CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date))
|
||||
{
|
||||
currentEntry.Date = date;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (line.StartsWith("DESCRIPTION:"))
|
||||
{
|
||||
string description = line.Substring("DESCRIPTION:".Length);
|
||||
currentEntry.Content = UnescapeIcsText(description);
|
||||
}
|
||||
else if (line.StartsWith("SUMMARY:") && !line.Contains("Chronolog"))
|
||||
{
|
||||
// If summary is not "Chronolog", use it as content if no description exists
|
||||
string summary = line.Substring("SUMMARY:".Length);
|
||||
if (string.IsNullOrEmpty(currentEntry.Content))
|
||||
{
|
||||
currentEntry.Content = UnescapeIcsText(summary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entries.OrderBy(e => e.Date).ToList();
|
||||
}
|
||||
|
||||
private string UnescapeIcsText(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return string.Empty;
|
||||
|
||||
// Unescape special characters according to RFC 5545
|
||||
return text
|
||||
.Replace("\\n", Environment.NewLine)
|
||||
.Replace("\\;", ";")
|
||||
.Replace("\\,", ",")
|
||||
.Replace("\\\\", "\\");
|
||||
}
|
||||
|
||||
private void GenerateOrgFile(List<DiaryEntry> entries, string outputFile)
|
||||
{
|
||||
var orgBuilder = new StringBuilder();
|
||||
|
||||
// Org file header
|
||||
orgBuilder.AppendLine("* Diary");
|
||||
orgBuilder.AppendLine();
|
||||
orgBuilder.AppendLine("Converted from calendar entries.");
|
||||
orgBuilder.AppendLine();
|
||||
|
||||
// Group entries by year and month for better organization
|
||||
var groupedEntries = entries
|
||||
.GroupBy(e => new { e.Date.Year, e.Date.Month })
|
||||
.OrderBy(g => g.Key.Year)
|
||||
.ThenBy(g => g.Key.Month);
|
||||
|
||||
foreach (var monthGroup in groupedEntries)
|
||||
{
|
||||
string monthName = new DateTime(monthGroup.Key.Year, monthGroup.Key.Month, 1)
|
||||
.ToString("MMMM yyyy", CultureInfo.InvariantCulture);
|
||||
|
||||
orgBuilder.AppendLine($"** {monthName}");
|
||||
orgBuilder.AppendLine();
|
||||
|
||||
foreach (var entry in monthGroup.OrderBy(e => e.Date))
|
||||
{
|
||||
orgBuilder.AppendLine($"*** {entry.Date:yyyy-MM-dd}");
|
||||
orgBuilder.AppendLine();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(entry.Content))
|
||||
{
|
||||
orgBuilder.AppendLine(entry.Content);
|
||||
}
|
||||
else
|
||||
{
|
||||
orgBuilder.AppendLine("(No content)");
|
||||
}
|
||||
|
||||
orgBuilder.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
File.WriteAllText(outputFile, orgBuilder.ToString(), Encoding.UTF8);
|
||||
}
|
||||
}
|
||||
|
||||
public class DiaryEntry
|
||||
{
|
||||
public DateTime Date { get; set; }
|
||||
public string Content { get; set; } = string.Empty;
|
||||
}
|
||||
134
README.md
Normal file
134
README.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# Org2Ics - Bidirectional Org/iCalendar Converter
|
||||
|
||||
A C# console application that provides bidirectional conversion between .org diary files and .ics (iCalendar) format.
|
||||
|
||||
## Description
|
||||
|
||||
This tool converts between .org files containing diary entries and iCalendar (.ics) files. It supports:
|
||||
- **Org to ICS**: Convert diary entries to all-day calendar events named "Chronolog"
|
||||
- **ICS to Org**: Convert calendar events back to org diary format with proper date headers
|
||||
|
||||
## Features
|
||||
|
||||
- **Bidirectional conversion** between .org and .ics formats
|
||||
- **Auto-detection** of input file format based on file extension
|
||||
- **Org to ICS conversion**:
|
||||
- Parses .org files with level 3 headings (***) containing dates in YYYY-MM-DD format
|
||||
- Extracts diary content for each date entry
|
||||
- Creates all-day events with the title "Chronolog"
|
||||
- Includes diary content as event descriptions
|
||||
- **ICS to Org conversion**:
|
||||
- Parses standard .ics calendar files
|
||||
- Extracts event dates and descriptions
|
||||
- Organizes entries by year and month
|
||||
- Creates proper org-mode structure with level 3 date headers
|
||||
- **Proper character escaping** for both formats
|
||||
- **Round-trip compatibility** for seamless conversion between formats
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
dotnet run <input.org|input.ics> [output.ics|output.org]
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
- `input.org|input.ics`: Path to the input file (required)
|
||||
- `.org` files will be converted to `.ics` format
|
||||
- `.ics` files will be converted to `.org` format
|
||||
- `output.ics|output.org`: Path to the output file (optional, auto-determined if not specified)
|
||||
|
||||
### Examples
|
||||
|
||||
```bash
|
||||
# Convert diary.org to diary.ics
|
||||
dotnet run diary.org
|
||||
|
||||
# Convert calendar.ics to calendar.org
|
||||
dotnet run calendar.ics
|
||||
|
||||
# Specify custom output filename
|
||||
dotnet run diary.org my-calendar.ics
|
||||
dotnet run calendar.ics my-diary.org
|
||||
|
||||
# Round-trip conversion
|
||||
dotnet run diary.org calendar.ics
|
||||
dotnet run calendar.ics diary-restored.org
|
||||
```
|
||||
|
||||
## File Format Support
|
||||
|
||||
### Org File Format (.org → .ics)
|
||||
|
||||
The converter expects .org files with the following structure:
|
||||
|
||||
```org
|
||||
* My Diary
|
||||
|
||||
** Month Section
|
||||
|
||||
*** 2025-01-15
|
||||
|
||||
This is the diary content for January 15th, 2025.
|
||||
It can span multiple lines and paragraphs.
|
||||
|
||||
*** 2025-01-16
|
||||
|
||||
Another diary entry for the next day.
|
||||
|
||||
** Another Section
|
||||
|
||||
*** 2025-02-01
|
||||
|
||||
February entry content here.
|
||||
```
|
||||
|
||||
**Requirements:**
|
||||
- Level 3 headings (starting with `***`) must contain dates in `YYYY-MM-DD` format
|
||||
- Everything after a date heading until the next heading becomes the diary content for that date
|
||||
- Non-date headings are ignored
|
||||
|
||||
### ICS File Format (.ics → .org)
|
||||
|
||||
The converter can parse standard iCalendar files and extracts:
|
||||
- Event dates (both all-day and timed events)
|
||||
- Event descriptions or summaries as diary content
|
||||
- Events are organized chronologically and grouped by month
|
||||
|
||||
**Supported:**
|
||||
- `DTSTART;VALUE=DATE:` (all-day events)
|
||||
- `DTSTART:` (timed events - date portion used)
|
||||
- `DESCRIPTION:` field content
|
||||
- `SUMMARY:` field content (when no description available)
|
||||
- Proper unescaping of iCalendar text formatting
|
||||
|
||||
## Output Formats
|
||||
|
||||
### Generated .ics Files (from .org)
|
||||
- Standard iCalendar format (RFC 5545 compliant)
|
||||
- All-day events spanning from the diary date to the next day
|
||||
- Event title: "Chronolog"
|
||||
- Event description: The diary content for that date
|
||||
- Unique identifiers for each event
|
||||
|
||||
### Generated .org Files (from .ics)
|
||||
- Proper org-mode structure with hierarchical headings
|
||||
- Level 1: "Diary" (root heading)
|
||||
- Level 2: Month and year groupings (e.g., "January 2025")
|
||||
- Level 3: Individual date entries (e.g., "*** 2025-01-15")
|
||||
- Content: Event descriptions properly formatted for org-mode
|
||||
|
||||
## Building
|
||||
|
||||
```bash
|
||||
dotnet build
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- .NET 8.0 or higher
|
||||
- No additional dependencies required
|
||||
|
||||
## License
|
||||
|
||||
This project is provided as-is for educational and personal use.
|
||||
38
samples/sample-diary-converted.org
Normal file
38
samples/sample-diary-converted.org
Normal file
@@ -0,0 +1,38 @@
|
||||
* Diary
|
||||
|
||||
Converted from calendar entries.
|
||||
|
||||
** January 2025
|
||||
|
||||
*** 2025-01-15
|
||||
|
||||
Today was a great day! I had a wonderful meeting with my colleagues and we discussed the new project plans. The weather was sunny and I went for a walk in the park.
|
||||
|
||||
I also read a good book in the evening.
|
||||
|
||||
*** 2025-01-16
|
||||
|
||||
Worked on the new features for our application. Made good progress on the user interface improvements.
|
||||
|
||||
Had dinner with friends at the new restaurant downtown.
|
||||
|
||||
** February 2025
|
||||
|
||||
*** 2025-02-01
|
||||
|
||||
Start of a new month! Set new goals for February:
|
||||
- Complete the project documentation
|
||||
- Exercise regularly
|
||||
- Learn a new programming language
|
||||
|
||||
*** 2025-02-14
|
||||
|
||||
Valentine's Day! Spent time with family and had a lovely dinner.
|
||||
|
||||
*** 2025-02-28
|
||||
|
||||
Last day of February. Reflecting on the month's achievements:
|
||||
- Successfully completed 3 major tasks
|
||||
- Improved my coding skills
|
||||
- Read 2 interesting books
|
||||
|
||||
46
samples/sample-diary.ics
Normal file
46
samples/sample-diary.ics
Normal file
@@ -0,0 +1,46 @@
|
||||
BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
PRODID:-//Org2Ics//Org2Ics//EN
|
||||
CALSCALE:GREGORIAN
|
||||
METHOD:PUBLISH
|
||||
BEGIN:VEVENT
|
||||
UID:chronolog-2025-01-15@org2ics
|
||||
DTSTAMP:20250830T081602Z
|
||||
DTSTART;VALUE=DATE:20250115
|
||||
DTEND;VALUE=DATE:20250116
|
||||
SUMMARY:Chronolog
|
||||
DESCRIPTION:Today was a great day! I had a wonderful meeting with my colleagues and we discussed the new project plans. The weather was sunny and I went for a walk in the park.\n\nI also read a good book in the evening.
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:chronolog-2025-01-16@org2ics
|
||||
DTSTAMP:20250830T081602Z
|
||||
DTSTART;VALUE=DATE:20250116
|
||||
DTEND;VALUE=DATE:20250117
|
||||
SUMMARY:Chronolog
|
||||
DESCRIPTION:Worked on the new features for our application. Made good progress on the user interface improvements.\n\nHad dinner with friends at the new restaurant downtown.
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:chronolog-2025-02-01@org2ics
|
||||
DTSTAMP:20250830T081602Z
|
||||
DTSTART;VALUE=DATE:20250201
|
||||
DTEND;VALUE=DATE:20250202
|
||||
SUMMARY:Chronolog
|
||||
DESCRIPTION:Start of a new month! Set new goals for February:\n- Complete the project documentation\n- Exercise regularly\n- Learn a new programming language
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:chronolog-2025-02-14@org2ics
|
||||
DTSTAMP:20250830T081602Z
|
||||
DTSTART;VALUE=DATE:20250214
|
||||
DTEND;VALUE=DATE:20250215
|
||||
SUMMARY:Chronolog
|
||||
DESCRIPTION:Valentine's Day! Spent time with family and had a lovely dinner.
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:chronolog-2025-02-28@org2ics
|
||||
DTSTAMP:20250830T081602Z
|
||||
DTSTART;VALUE=DATE:20250228
|
||||
DTEND;VALUE=DATE:20250301
|
||||
SUMMARY:Chronolog
|
||||
DESCRIPTION:Last day of February. Reflecting on the month's achievements:\n- Successfully completed 3 major tasks\n- Improved my coding skills\n- Read 2 interesting books
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
41
samples/sample-diary.org
Normal file
41
samples/sample-diary.org
Normal file
@@ -0,0 +1,41 @@
|
||||
* My Diary
|
||||
|
||||
This is my personal diary file.
|
||||
|
||||
** January 2025
|
||||
|
||||
*** 2025-01-15
|
||||
|
||||
Today was a great day! I had a wonderful meeting with my colleagues and we discussed the new project plans. The weather was sunny and I went for a walk in the park.
|
||||
|
||||
I also read a good book in the evening.
|
||||
|
||||
*** 2025-01-16
|
||||
|
||||
Worked on the new features for our application. Made good progress on the user interface improvements.
|
||||
|
||||
Had dinner with friends at the new restaurant downtown.
|
||||
|
||||
** February 2025
|
||||
|
||||
*** 2025-02-01
|
||||
|
||||
Start of a new month! Set new goals for February:
|
||||
- Complete the project documentation
|
||||
- Exercise regularly
|
||||
- Learn a new programming language
|
||||
|
||||
*** 2025-02-14
|
||||
|
||||
Valentine's Day! Spent time with family and had a lovely dinner.
|
||||
|
||||
* Some other section
|
||||
|
||||
This is not a diary entry and should be ignored.
|
||||
|
||||
*** 2025-02-28
|
||||
|
||||
Last day of February. Reflecting on the month's achievements:
|
||||
- Successfully completed 3 major tasks
|
||||
- Improved my coding skills
|
||||
- Read 2 interesting books
|
||||
24
samples/test-calendar-converted.org
Normal file
24
samples/test-calendar-converted.org
Normal file
@@ -0,0 +1,24 @@
|
||||
* Diary
|
||||
|
||||
Converted from calendar entries.
|
||||
|
||||
** September 2025
|
||||
|
||||
*** 2025-09-01
|
||||
|
||||
Spent the weekend relaxing at home. Watched some movies and caught up on reading.
|
||||
|
||||
*** 2025-09-03
|
||||
|
||||
First day back after the long weekend. Had several meetings and started planning the new quarter.
|
||||
|
||||
*** 2025-09-15
|
||||
|
||||
Company organized a team building event at the local park. Great fun with colleagues, lots of games and good food.
|
||||
|
||||
** October 2025
|
||||
|
||||
*** 2025-10-01
|
||||
|
||||
Important client meeting to discuss project requirements and timeline.
|
||||
|
||||
38
samples/test-calendar-roundtrip.ics
Normal file
38
samples/test-calendar-roundtrip.ics
Normal file
@@ -0,0 +1,38 @@
|
||||
BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
PRODID:-//Org2Ics//Org2Ics//EN
|
||||
CALSCALE:GREGORIAN
|
||||
METHOD:PUBLISH
|
||||
BEGIN:VEVENT
|
||||
UID:chronolog-2025-09-01@org2ics
|
||||
DTSTAMP:20250830T082255Z
|
||||
DTSTART;VALUE=DATE:20250901
|
||||
DTEND;VALUE=DATE:20250902
|
||||
SUMMARY:Chronolog
|
||||
DESCRIPTION:Spent the weekend relaxing at home. Watched some movies and caught up on reading.
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:chronolog-2025-09-03@org2ics
|
||||
DTSTAMP:20250830T082255Z
|
||||
DTSTART;VALUE=DATE:20250903
|
||||
DTEND;VALUE=DATE:20250904
|
||||
SUMMARY:Chronolog
|
||||
DESCRIPTION:First day back after the long weekend. Had several meetings and started planning the new quarter.
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:chronolog-2025-09-15@org2ics
|
||||
DTSTAMP:20250830T082255Z
|
||||
DTSTART;VALUE=DATE:20250915
|
||||
DTEND;VALUE=DATE:20250916
|
||||
SUMMARY:Chronolog
|
||||
DESCRIPTION:Company organized a team building event at the local park. Great fun with colleagues\, lots of games and good food.
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:chronolog-2025-10-01@org2ics
|
||||
DTSTAMP:20250830T082255Z
|
||||
DTSTART;VALUE=DATE:20251001
|
||||
DTEND;VALUE=DATE:20251002
|
||||
SUMMARY:Chronolog
|
||||
DESCRIPTION:Important client meeting to discuss project requirements and timeline.
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
38
samples/test-calendar.ics
Normal file
38
samples/test-calendar.ics
Normal file
@@ -0,0 +1,38 @@
|
||||
BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
PRODID:-//Example Corp//CalDAV Client//EN
|
||||
CALSCALE:GREGORIAN
|
||||
METHOD:PUBLISH
|
||||
BEGIN:VEVENT
|
||||
UID:event1@example.com
|
||||
DTSTAMP:20250830T100000Z
|
||||
DTSTART;VALUE=DATE:20250901
|
||||
DTEND;VALUE=DATE:20250902
|
||||
SUMMARY:Labor Day Weekend
|
||||
DESCRIPTION:Spent the weekend relaxing at home. Watched some movies and caught up on reading.
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:event2@example.com
|
||||
DTSTAMP:20250830T100000Z
|
||||
DTSTART;VALUE=DATE:20250903
|
||||
DTEND;VALUE=DATE:20250904
|
||||
SUMMARY:Back to Work
|
||||
DESCRIPTION:First day back after the long weekend. Had several meetings and started planning the new quarter.
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:event3@example.com
|
||||
DTSTAMP:20250830T100000Z
|
||||
DTSTART;VALUE=DATE:20250915
|
||||
DTEND;VALUE=DATE:20250916
|
||||
SUMMARY:Team Building Event
|
||||
DESCRIPTION:Company organized a team building event at the local park. Great fun with colleagues\, lots of games and good food.
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:event4@example.com
|
||||
DTSTAMP:20250830T100000Z
|
||||
DTSTART:20251001T140000Z
|
||||
DTEND:20251001T160000Z
|
||||
SUMMARY:Meeting with Client
|
||||
DESCRIPTION:Important client meeting to discuss project requirements and timeline.
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
Reference in New Issue
Block a user