GET /calendars/primary/events?maxResults=10&singleEvents=true&syncToken=CPDAlvWDx70CEPDAlvWDx
// Result contains the following
"nextPageToken":"CiAKGjBpNDd2Nmp2Zml2cXRwYjBpOXA",
正在检索下一页
GET /calendars/primary/events?maxResults=10&singleEvents=true&syncToken=CPDAlvWDx70CEPDAlvWDx&pageToken=CiAKGjBpNDd2Nmp2Zml2cXRwYjBpOXA
下面的示例代码段演示了如何将同步令牌与 Java 客户端库搭配使用。首次调用 run 方法时,它会执行完整同步并存储同步令牌。在后续每次执行时,它都会加载已保存的同步令牌并执行增量同步。
privatestaticvoidrun()throwsIOException{// Construct the {@link Calendar.Events.List} request, but don't execute it yet.Calendar.Events.Listrequest=client.events().list("primary");// Load the sync token stored from the last execution, if any.StringsyncToken=syncSettingsDataStore.get(SYNC_TOKEN_KEY);if(syncToken==null){System.out.println("Performing full sync.");// Set the filters you want to use during the full sync. Sync tokens aren't compatible with// most filters, but you may want to limit your full sync to only a certain date range.// In this example we are only syncing events up to a year old.DateoneYearAgo=Utils.getRelativeDate(java.util.Calendar.YEAR,-1);request.setTimeMin(newDateTime(oneYearAgo,TimeZone.getTimeZone("UTC")));}else{System.out.println("Performing incremental sync.");request.setSyncToken(syncToken);}// Retrieve the events, one page at a time.StringpageToken=null;Eventsevents=null;do{request.setPageToken(pageToken);try{events=request.execute();}catch(GoogleJsonResponseExceptione){if(e.getStatusCode()==410){// A 410 status code, "Gone", indicates that the sync token is invalid.System.out.println("Invalid sync token, clearing event store and re-syncing.");syncSettingsDataStore.delete(SYNC_TOKEN_KEY);eventDataStore.clear();run();}else{throwe;}}List<Event>items=events.getItems();if(items.size()==0){System.out.println("No new events to sync.");}else{for(Eventevent:items){syncEvent(event);}}pageToken=events.getNextPageToken();}while(pageToken!=null);// Store the sync token from the last request to be used during the next execution.syncSettingsDataStore.set(SYNC_TOKEN_KEY,events.getNextSyncToken());System.out.println("Sync complete.");}
[null,null,["最后更新时间 (UTC):2025-08-29。"],[],[],null,["# Synchronize resources efficiently\n\nThis guide describes how to\nimplement \"incremental synchronization\" of calendar data. Using this\nmethod, you can keep data for all calendar collections in sync while saving\nbandwidth.\n\nContents\n--------\n\nOverview\n--------\n\nIncremental synchronization consists of two stages:\n\n1. Initial full sync is performed once at the very beginning in order to fully\n synchronize the client's state with the server's state. The client will obtain\n a sync token that it needs to persist.\n\n2. Incremental sync is performed repeatedly and updates the client with all\n the changes that happened ever since the previous sync. Each time, the client\n provides the previous sync token it obtained from the server and stores the new sync token from the response.\n\n| A **sync token** is a piece of data exchanged between the server and the client, and has a critical role in the synchronization process. An example would look like the following:\n|\n| `\"nextSyncToken\": \"CPDAlvWDx70CEPDAlvWDx70CGAU=\",`\n\nInitial full sync\n-----------------\n\nThe initial full sync is the original request for all the resources of the\ncollection you want to synchronize. You can optionally restrict the list\nrequest using request parameters if you only want to synchronize a specific\nsubset of resources.\n\nIn the response to the list operation, you will find a field called\n`nextSyncToken` representing a sync token. You'll need to store the value of\n`nextSyncToken`. If the result set is too large and the response gets\n[paginated](/workspace/calendar/v3/pagination), then the `nextSyncToken`\nfield is present only on the very last page.\n| You don't need to worry about any new entries appearing while you are paginating --- they won't be missed. The information needed for the server to generate a correct sync token is encoded in the page token.\n\nIncremental sync\n----------------\n\nIncremental sync allows you to retrieve all the resources that have been\nmodified since the last sync request. To do this, you need to perform a list\nrequest with your most recent sync token specified in the `syncToken` field.\nKeep in mind that the result will always contain deleted entries, so that the\nclients get the chance to remove them from storage.\n\nIn cases where a large number of resources have changed since the last\nincremental sync request, you may find a `pageToken` instead of a `syncToken` in the list result. In these cases you'll need to perform the exact same\nlist query as was used for retrieval of the first page in the incremental sync\n(with the exact same `syncToken`), append the `pageToken` to it and\npaginate through all the following requests until you find another `syncToken` on the last page. Make sure to store this `syncToken` for the next sync\nrequest in the future.\n\nHere are example queries for a case requiring incremental paginated sync:\n\n**Original query** \n\n GET /calendars/primary/events?maxResults=10&singleEvents=true&syncToken=CPDAlvWDx70CEPDAlvWDx\n\n // Result contains the following\n\n \"nextPageToken\":\"CiAKGjBpNDd2Nmp2Zml2cXRwYjBpOXA\",\n\n**Retrieving next page** \n\n GET /calendars/primary/events?maxResults=10&singleEvents=true&syncToken=CPDAlvWDx70CEPDAlvWDx&pageToken=CiAKGjBpNDd2Nmp2Zml2cXRwYjBpOXA\n\n| The set of query parameters that can be used on incremental syncs is restricted. Each list request should use the same set of query parameters, including the initial request. For the individual restrictions on each collection, see the corresponding documentation for list requests. The response code for list queries containing disallowed restrictions is `400`.\n\nFull sync required by server\n----------------------------\n\nSometimes sync tokens are invalidated by the server, for various reasons\nincluding token expiration or changes in related ACLs.\nIn such cases, the server will respond to an incremental request with a\nresponse code `410`. This should trigger a full wipe of the client's store\nand a new full sync.\n\nSample code\n-----------\n\nThe snippet of sample code below demonstrates how to use sync tokens with the\n[Java client library](/api-client-library/java/apis/calendar/v3). The first time\nthe run method is called it will perform a full sync and store the sync token.\nOn each subsequent execution it will load the saved sync token and perform an\nincremental sync. \n\n```java\n private static void run() throws IOException {\n // Construct the {@link Calendar.Events.List} request, but don't execute it yet.\n Calendar.Events.List request = client.events().list(\"primary\");\n\n // Load the sync token stored from the last execution, if any.\n String syncToken = syncSettingsDataStore.get(SYNC_TOKEN_KEY);\n if (syncToken == null) {\n System.out.println(\"Performing full sync.\");\n\n // Set the filters you want to use during the full sync. Sync tokens aren't compatible with\n // most filters, but you may want to limit your full sync to only a certain date range.\n // In this example we are only syncing events up to a year old.\n Date oneYearAgo = Utils.getRelativeDate(java.util.Calendar.YEAR, -1);\n request.setTimeMin(new DateTime(oneYearAgo, TimeZone.getTimeZone(\"UTC\")));\n } else {\n System.out.println(\"Performing incremental sync.\");\n request.setSyncToken(syncToken);\n }\n\n // Retrieve the events, one page at a time.\n String pageToken = null;\n Events events = null;\n do {\n request.setPageToken(pageToken);\n\n try {\n events = request.execute();\n } catch (GoogleJsonResponseException e) {\n if (e.getStatusCode() == 410) {\n // A 410 status code, \"Gone\", indicates that the sync token is invalid.\n System.out.println(\"Invalid sync token, clearing event store and re-syncing.\");\n syncSettingsDataStore.delete(SYNC_TOKEN_KEY);\n eventDataStore.clear();\n run();\n } else {\n throw e;\n }\n }\n\n List\u003cEvent\u003e items = events.getItems();\n if (items.size() == 0) {\n System.out.println(\"No new events to sync.\");\n } else {\n for (Event event : items) {\n syncEvent(event);\n }\n }\n\n pageToken = events.getNextPageToken();\n } while (pageToken != null);\n\n // Store the sync token from the last request to be used during the next execution.\n syncSettingsDataStore.set(SYNC_TOKEN_KEY, events.getNextSyncToken());\n\n System.out.println(\"Sync complete.\");\n }https://github.com/googleworkspace/java-samples/blob/26cb124371d51cb5cb8e6c4a3db6422bbef586fb/calendar/sync/src/main/java/com/google/api/services/samples/calendar/sync/SyncTokenSample.java\n```\n\nLegacy synchronization\n----------------------\n\nFor event collections, it is still possible to do synchronization in the\nlegacy manner by preserving the value of the updated field from an events list\nrequest and then using the `modifiedSince` field to retrieve updated events.\nThis approach is no longer recommended as it is more error-prone with respect\nto missed updates (for example if does not enforce query restrictions).\nFurthermore, it is available only for events."]]